#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_statistics_double.h>
#include <math.h>
#include "tz_error.h"
#include "tz_constant.h"
#include "tz_voxel_linked_list.h"
#include "tz_stack_sampling.h"
#include "tz_voxel_graphics.h"
#include "tz_neurotrace.h"
#include "tz_stack_math.h"
#include "tz_stack_utils.h"
#include "tz_objdetect.h"
#include "tz_voxeltrans.h"
#include "tz_stack_stat.h"
#include "tz_stack_draw.h"
#include "tz_geo3d_vector.h"
#include "tz_stack_bwmorph.h"
#include "tz_stack_bwdist.h"
#include "tz_stack_threshold.h"

INIT_EXCEPTION_MAIN(e)

int main(int argc, char* argv[])
{
  char neuron_name[100];
  if (argc == 1) {
    strcpy(neuron_name, "fly_neuron");
  } else {
    strcpy(neuron_name, argv[1]);
  }

  char file_path[100];

  sprintf(file_path, "../data/%s/traced.tif", neuron_name);
  Stack *stack = Read_Stack(file_path);

  sprintf(file_path, "../data/%s/soma.tif", neuron_name);
  Stack *label = Read_Stack(file_path);

  Stack *label2 = Copy_Stack(label);

  Rgb_Color color;
  Set_Color(&color, 0, 255, 0);

  Stack_Threshold(label, 2);
  Stack_Binarize(label);

  Stack_Threshold(label2, 1);
  Stack_Binarize(label2);
  Stack_Xor(label, label2, label2);

  sprintf(file_path, "../data/%s.tif", neuron_name);
  Stack *signal = Read_Stack(file_path);
  //label = Stack_Boundary_N(label, NULL, 8);
  //Stack_Label_Bwc(stack, label, color);
  Stack_Label_Color(stack, label, 5.4, 1.0, signal);

  //label2 = Stack_Boundary_N(label2, NULL, 8);
  //Set_Color(&color, 0, 0, 255);
  //Stack_Label_Bwc(stack, label2, color);
  Stack_Label_Color(stack, label2, 3.6, 1.0, signal);

  sprintf(file_path, "../data/%s/label.tif", neuron_name);
  Write_Stack(file_path, stack);

  Kill_Stack(signal);
  Kill_Stack(stack);
  Kill_Stack(label);
  Kill_Stack(label2);

  return 0;
}


/*
* -----------------------------------------------------------------
*  Pairwise Mixing Stirred Reaction Library --- pmsr_lib.h
*  Version: 1.6180
*  Date: Nov 16, 2010
* -----------------------------------------------------------------
*  Programmer: Americo Barbosa da Cunha Junior
*              americo.cunhajr@gmail.com
* -----------------------------------------------------------------
*  Copyright (c) 2010 by Americo Barbosa da Cunha Junior
*
*  This program is free software: you can redistribute it and/or
*  modify it under the terms of the GNU General Public License as
*  published by the Free Software Foundation, either version 3 of
*  the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  A copy of the GNU General Public License is available in
*  LICENSE.txt or http://www.gnu.org/licenses/.
* -----------------------------------------------------------------
*  This is the header file for the PMSR model.
* -----------------------------------------------------------------
*/

#ifndef __PMSR_LIB_H__
#define __PMSR_LIB_H__

#include <gsl/gsl_vector.h>
#include <gsl/gsl_rng.h>

/*
* ------------------------------------------------------------
*  Types: struct pmsr, pmsr_wrk
* ------------------------------------------------------------
* This structure contains fields of PMSR model.
*
* last update: Nov 5, 2009
* ------------------------------------------------------------
*/

typedef struct pmsr
{
    int *pmsr_idx;         /* particles index vector */
    gsl_vector **pmsr_ps;  /* particle system        */
} pmsr_wrk;
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
* function prototypes
*------------------------------------------------------------
*/

void pmsr_title();

int pmsr_input(unsigned long int *seed,
               unsigned int *Np,
               unsigned int *K,
               double *t0,
               double *delta_t,
               double *tau_res,
               double *tau_mix,
	           double *tau_pair,
               double *Tmax,
               double *Tmin);

pmsr_wrk *pmsr_alloc();

int pmsr_init(int Np,
              int Neq,
              pmsr_wrk *pmsr);

void pmsr_free(int Np,
               void **pmsr_bl);

void pmsr_set_all(int Np,
                  gsl_vector *phi,
                  pmsr_wrk *pmsr);

int pmsr_Nexc(int Np,
              double delta_t,
              double tau_res);

int pmsr_Npair(int Np,
               double delta_t,
               double tau_pair);

void pmsr_meanvar(int Np,
                  int k,
                  gsl_vector **ps,
                  double *mean,
                  double *var);

void pmsr_mixture(int Np,
                  int Neq,
                  double delta_t,
                  double tau_mix,
                  int *idx,
                  gsl_vector **ps);

void pmsr_iops(int Np,
               int Nexc,
               int Npair,
               gsl_rng *r,
               gsl_vector *phi,
               pmsr_wrk *pmsr);

#endif /* __PMSR_LIB_H__ */


#pragma once

#include "datastructures/PointBuffer.h"
#include "math/Vector3.h"
#include "proj_api.h"

#include <containers/Range.h>

#include <string>

#include <gsl/gsl>

class Point;
struct AABB;

/// <summary>
/// Spatial reference systems that the SRSTransformHelper can transform into
/// </summary>
enum class TargetSRS
{
  /// <summary>
  /// WGS84 specified with latitude, longitude (radians) and height over
  /// ellipsoid (meters)
  /// </summary>
  WGS84,
  /// <summary>
  /// Cesium world coordinate system (WGS84 geocentric)
  /// </summary>
  CesiumWorld
};

/// <summary>
/// Utility class for transforming positions between spatial reference systems
/// </summary>
struct SRSTransformHelper
{
  virtual ~SRSTransformHelper();

  /// <summary>
  /// Transforms a range of positions into the target SRS. Transformation
  /// modifies the source points
  /// </summary>
  virtual void transformPositionsTo(TargetSRS targetSRS,
                                    gsl::span<Vector3<double>> positions) const = 0;

  /// <summary>
  /// Transforms a range of position from the given SRS back into source
  /// coordinate space
  /// </summary>
  virtual void transformPositionToSourceFrom(TargetSRS currentSRS,
                                             gsl::span<Vector3<double>> positions) const = 0;

  virtual void transformPointsTo(TargetSRS targetSRS,
                                 gsl::span<PointBuffer::PointReference> points) const = 0;

  virtual void transformPointsTo(TargetSRS targetSRS,
                                 util::Range<PointBuffer::PointIterator> points) const = 0;

  /// <summary>
  /// Transforms a range of axis-aligned bounding boxes into the target SRS.
  /// Transformation happens in-place. The axis-aligned property will be
  /// preserved after the transformation, which can result in an increase in
  /// volume of the AABBs
  /// </summary>
  virtual void transformAABBsTo(TargetSRS targetSRS, gsl::span<AABB> aabbs) const = 0;
};

/// <summary>
/// Identity transformation, i.e. a transformation that does nothing
/// </summary>
struct IdentityTransform : SRSTransformHelper
{
  virtual ~IdentityTransform();

  void transformPositionsTo(TargetSRS targetSRS,
                            gsl::span<Vector3<double>> positions) const override;
  void transformPositionToSourceFrom(TargetSRS currentSRS,
                                     gsl::span<Vector3<double>> positions) const override;
  void transformPointsTo(TargetSRS targetSRS,
                         gsl::span<PointBuffer::PointReference> points) const override;
  void transformPointsTo(TargetSRS targetSRS,
                         util::Range<PointBuffer::PointIterator> points) const override;
  void transformAABBsTo(TargetSRS targetSRS, gsl::span<AABB> aabbs) const override;
};

/// <summary>
/// Transformation based on proj4 coordinate system conversion
/// </summary>
struct Proj4Transform : SRSTransformHelper
{
  explicit Proj4Transform(const std::string& sourceTransformation);
  virtual ~Proj4Transform();

  void transformPositionsTo(TargetSRS targetSRS,
                            gsl::span<Vector3<double>> positions) const override;
  void transformPositionToSourceFrom(TargetSRS currentSRS,
                                     gsl::span<Vector3<double>> positions) const override;
  void transformPointsTo(TargetSRS targetSRS,
                         gsl::span<PointBuffer::PointReference> points) const override;
  void transformPointsTo(TargetSRS targetSRS,
                         util::Range<PointBuffer::PointIterator> points) const override;
  void transformAABBsTo(TargetSRS targetSRS, gsl::span<AABB> aabbs) const override;

private:
  projPJ getTargetTransformation(TargetSRS targetSRS) const;

  projPJ _sourceTransformation;
  projPJ _wgs84;
  projPJ _cesiumWorld;
};

/// <summary>
/// Finds the smallest point of the given points and subtracts it from all
/// points. This sets the origin of the points to the smallest point. The
/// smallest point prior to subtraction is returned
/// </summary>
Vector3<double>
setOriginToSmallestPoint(std::vector<Vector3<double>>& points);

template<typename Iter>
Vector3<double>
setOriginToSmallestPoint(Iter points_begin, Iter points_end)
{
  const auto dblMax = std::numeric_limits<double>::max();
  const auto smallestPoint =
    std::accumulate(points_begin,
                    points_end,
                    Vector3<double>{ dblMax, dblMax, dblMax },
                    [](const auto& accum, const auto& point) {
                      return Vector3<double>::minByAxis(accum, point.position());
                    });

  std::for_each(
    points_begin, points_end, [smallestPoint](auto& point) { point.position() -= smallestPoint; });

  return smallestPoint;
}


/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#pragma once

#include <cblas.h>
#include <cuda_runtime_api.h>

#include <boost/shared_ptr.hpp>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "modules/perception/base/blob.h"
#include "modules/perception/base/image.h"

namespace apollo {
namespace perception {
namespace inference {
class GPUL2Norm {
 public:
  void L2Norm(base::Blob<float> *input_data);

 private:
  base::Blob<float> scale_;
  base::Blob<float> ones_;
  base::Blob<float> square_;
};

void GPUGemmFloat(const CBLAS_TRANSPOSE TransA, const CBLAS_TRANSPOSE TransB,
                  const int M, const int N, const int K, const float alpha,
                  const float *A, const float *B, const float beta, float *C);
void GPUMultiFloat(const int n, const float *a, const float *b, float *result);
void GPUMSetFloat(const int n, const float alpha, float *result);

}  // namespace inference
}  // namespace perception
}  // namespace apollo


/**
 *
 * @file qwrapper_dgemv.c
 *
 *  PLASMA core_blas quark wrapper
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Mark Gates
 * @author Mathieu Faverge
 * @date 2010-11-15
 * @generated d Tue Jan  7 11:44:59 2014
 *
 **/
#include <cblas.h>
#include "common.h"

/***************************************************************************//**
 *
 **/
void QUARK_CORE_dgemv(Quark *quark, Quark_Task_Flags *task_flags,
                      PLASMA_enum trans, int m, int n,
                      double alpha, const double *A, int lda,
                                                const double *x, int incx,
                      double beta,        double *y, int incy)
{
    DAG_CORE_GEMV;
    QUARK_Insert_Task(quark, CORE_dgemv_quark, task_flags,
        sizeof(PLASMA_enum),             &trans,  VALUE,
        sizeof(int),                     &m,      VALUE,
        sizeof(int),                     &n,      VALUE,
        sizeof(double),      &alpha,  VALUE,
        sizeof(double)*m*n,  A,               INPUT,
        sizeof(int),                     &lda,    VALUE,
        sizeof(double)*n,    x,               INPUT,
        sizeof(int),                     &incx,   VALUE,
        sizeof(double),      &beta,   VALUE,
        sizeof(double)*m,    y,               INOUT,
        sizeof(int),                     &incy,   VALUE,
        0);
}

/***************************************************************************//**
 *
 **/
#if defined(PLASMA_HAVE_WEAK)
#pragma weak CORE_dgemv_quark = PCORE_dgemv_quark
#define CORE_dgemv_quark PCORE_dgemv_quark
#endif
void CORE_dgemv_quark(Quark *quark)
{
    PLASMA_enum trans;
    int m, n, lda, incx, incy;
    double alpha, beta;
    const double *A, *x;
    double *y;

    quark_unpack_args_11( quark, trans, m, n, alpha, A, lda, x, incx, beta, y, incy );
    cblas_dgemv(
        CblasColMajor,
        (CBLAS_TRANSPOSE)trans,
        m, n,
        (alpha), A, lda,
                            x, incx,
        (beta),  y, incy);
}


#ifndef QRTRANSPOSE_H
#define QRTRANSPOSE_H

#include <gsl/gsl_matrix.h>
#include "QR.h"

/**
 * Compute and return the QR decomposition of a given matrix' transpose. If
 * `M` is passed to the constructor, the `getQ` function will return the Q
 * matrix in the decomposition M^T = QR et similis for `getR`.
 *
 * Convenient for computation of QR-backed nullspace (see NullspaceQR)
 */
class TransposeQR{
 public:
  TransposeQR(gsl_matrix* M);

  void updateFromMatrix();

  gsl_matrix* getMatrix() const;

  /** Return the Q-matrix from the decomposition M^T = QR */
  gsl_matrix* getQ() const;

  /** Return the R-matrix from the decomposition M^T = QR */
  gsl_matrix* getR() const;

 private:
  QR * const m_qr;
  gsl_matrix * const m_origMatrix;
};

#endif