/*******************************************************************************
 * Copyright 2013-2014 Sebastian Niemann <niemann@sra.uni-hannover.de>.
 *
 * Licensed under the MIT License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/MIT
 *
 * Developers:
 *   Sebastian Niemann - Lead developer
 *   Daniel Kiechle - Unit testing
 ******************************************************************************/
#include <iostream>
// EXIT_SUCCESS
using std::cout;
using std::endl;

#include <fstream>
using std::ofstream;

#define ARMA_USE_CXX11
#include <armadillo>
using arma::set_stream_err1;
using arma::set_stream_err2;
using arma::arma_rng;

#include <ExpectedDatum.cpp>
using armadilloJava::ExpectedDatum;

#include <ExpectedElemIndFill.cpp>
using armadilloJava::ExpectedElemIndFill;

#include <ExpectedGenColVec.cpp>
using armadilloJava::ExpectedGenColVec;

#include <ExpectedGenColVecElemInd.cpp>
using armadilloJava::ExpectedGenColVecElemInd;

#include <ExpectedGenColVecElemIndRange.cpp>
using armadilloJava::ExpectedGenColVecElemIndRange;

#include <ExpectedGenColVecElemInds.cpp>
using armadilloJava::ExpectedGenColVecElemInds;

#include <ExpectedGenColVecExp.cpp>
using armadilloJava::ExpectedGenColVecExp;

#include <ExpectedGenColVecGenColVec.cpp>
using armadilloJava::ExpectedGenColVecGenColVec;

#include <ExpectedGenColVecGenColVecNormal.cpp>
using armadilloJava::ExpectedGenColVecGenColVecNormal;

#include <ExpectedGenColVecGenDouble.cpp>
using armadilloJava::ExpectedGenColVecGenDouble;

#include <ExpectedGenColVecGenMat.cpp>
using armadilloJava::ExpectedGenColVecGenMat;

#include <ExpectedGenColVecGenRowVec.cpp>
using armadilloJava::ExpectedGenColVecGenRowVec;

#include <ExpectedGenColVecGenRowVecNormal.cpp>
using armadilloJava::ExpectedGenColVecGenRowVecNormal;

#include <ExpectedGenColVecMonColVec.cpp>
using armadilloJava::ExpectedGenColVecMonColVec;

#include <ExpectedGenColVecMonRowVec.cpp>
using armadilloJava::ExpectedGenColVecMonRowVec;

#include <ExpectedGenColVecNormal.cpp>
using armadilloJava::ExpectedGenColVecNormal;

#include <ExpectedGenColVecNumElems.cpp>
using armadilloJava::ExpectedGenColVecNumElems;

#include <ExpectedGenColVecNumRowsNumCols.cpp>
using armadilloJava::ExpectedGenColVecNumRowsNumCols;

#include <ExpectedGenColVecRowIndColInd.cpp>
using armadilloJava::ExpectedGenColVecRowIndColInd;

#include <ExpectedGenColVecRowIndColIndMatSize.cpp>
using armadilloJava::ExpectedGenColVecRowIndColIndMatSize;

#include <ExpectedGenColVecRowIndRangeColIndRange.cpp>
using armadilloJava::ExpectedGenColVecRowIndRangeColIndRange;

#include <ExpectedGenColVecSort.cpp>
using armadilloJava::ExpectedGenColVecSort;

#include <ExpectedGenColVecVecNormInt.cpp>
using armadilloJava::ExpectedGenColVecVecNormInt;

#include <ExpectedGenColVecVecNormString.cpp>
using armadilloJava::ExpectedGenColVecVecNormString;

#include <ExpectedGenDouble.cpp>
using armadilloJava::ExpectedGenDouble;

#include <ExpectedGenDoubleGenDouble.cpp>
using armadilloJava::ExpectedGenDoubleGenDouble;

#include <ExpectedGenDoubleGenDoubleNumElems.cpp>
using armadilloJava::ExpectedGenDoubleGenDoubleNumElems;

#include <ExpectedGenMat.cpp>
using armadilloJava::ExpectedGenMat;

#include <ExpectedGenMatColInd.cpp>
using armadilloJava::ExpectedGenMatColInd;

#include <ExpectedGenMatColIndRange.cpp>
using armadilloJava::ExpectedGenMatColIndRange;

#include <ExpectedGenMatColInds.cpp>
using armadilloJava::ExpectedGenMatColInds;

#include <ExpectedGenMatDim.cpp>
using armadilloJava::ExpectedGenMatDim;

#include <ExpectedGenMatElemInd.cpp>
using armadilloJava::ExpectedGenMatElemInd;

#include <ExpectedGenMatElemIndRange.cpp>
using armadilloJava::ExpectedGenMatElemIndRange;

#include <ExpectedGenMatElemInds.cpp>
using armadilloJava::ExpectedGenMatElemInds;

#include <ExpectedGenMatExp.cpp>
using armadilloJava::ExpectedGenMatExp;

#include <ExpectedGenMatGenColVec.cpp>
using armadilloJava::ExpectedGenMatGenColVec;

#include <ExpectedGenMatGenDouble.cpp>
using armadilloJava::ExpectedGenMatGenDouble;

#include <ExpectedGenMatGenMat.cpp>
using armadilloJava::ExpectedGenMatGenMat;

#include <ExpectedGenMatGenMatNormal.cpp>
using armadilloJava::ExpectedGenMatGenMatNormal;

#include <ExpectedGenMatGenRowVec.cpp>
using armadilloJava::ExpectedGenMatGenRowVec;

#include <ExpectedGenMatMatNormInt.cpp>
using armadilloJava::ExpectedGenMatMatNormInt;

#include <ExpectedGenMatMatNormString.cpp>
using armadilloJava::ExpectedGenMatMatNormString;

#include <ExpectedGenMatMonColVec.cpp>
using armadilloJava::ExpectedGenMatMonColVec;

#include <ExpectedGenMatMonColVecDim.cpp>
using armadilloJava::ExpectedGenMatMonColVecDim;

#include <ExpectedGenMatMonRowVec.cpp>
using armadilloJava::ExpectedGenMatMonRowVec;

#include <ExpectedGenMatMonRowVecDim.cpp>
using armadilloJava::ExpectedGenMatMonRowVecDim;

#include <ExpectedGenMatNormal.cpp>
using armadilloJava::ExpectedGenMatNormal;

#include <ExpectedGenMatNormalDim.cpp>
using armadilloJava::ExpectedGenMatNormalDim;

#include <ExpectedGenMatNumElems.cpp>
using armadilloJava::ExpectedGenMatNumElems;

#include <ExpectedGenMatNumElemsDim.cpp>
using armadilloJava::ExpectedGenMatNumElemsDim;

#include <ExpectedGenMatNumRowsNumCols.cpp>
using armadilloJava::ExpectedGenMatNumRowsNumCols;

#include <ExpectedGenMatRowInd.cpp>
using armadilloJava::ExpectedGenMatRowInd;

#include <ExpectedGenMatRowIndColInd.cpp>
using armadilloJava::ExpectedGenMatRowIndColInd;

#include <ExpectedGenMatRowIndColIndMatSize.cpp>
using armadilloJava::ExpectedGenMatRowIndColIndMatSize;

#include <ExpectedGenMatRowIndColIndRange.cpp>
using armadilloJava::ExpectedGenMatRowIndColIndRange;

#include <ExpectedGenMatRowIndRange.cpp>
using armadilloJava::ExpectedGenMatRowIndRange;

#include <ExpectedGenMatRowIndRangeColInd.cpp>
using armadilloJava::ExpectedGenMatRowIndRangeColInd;

#include <ExpectedGenMatRowIndRangeColIndRange.cpp>
using armadilloJava::ExpectedGenMatRowIndRangeColIndRange;

#include <ExpectedGenMatRowInds.cpp>
using armadilloJava::ExpectedGenMatRowInds;

#include <ExpectedGenMatRowIndsColInds.cpp>
using armadilloJava::ExpectedGenMatRowIndsColInds;

#include <ExpectedGenMatSinValSel.cpp>
using armadilloJava::ExpectedGenMatSinValSel;

#include <ExpectedGenMatSinValTol.cpp>
using armadilloJava::ExpectedGenMatSinValTol;

#include <ExpectedGenMatSort.cpp>
using armadilloJava::ExpectedGenMatSort;

#include <ExpectedGenMatSortDim.cpp>
using armadilloJava::ExpectedGenMatSortDim;

#include <ExpectedGenMatVecNormInt.cpp>
using armadilloJava::ExpectedGenMatVecNormInt;

#include <ExpectedGenRowVec.cpp>
using armadilloJava::ExpectedGenRowVec;

#include <ExpectedGenRowVecElemInd.cpp>
using armadilloJava::ExpectedGenRowVecElemInd;

#include <ExpectedGenRowVecElemIndRange.cpp>
using armadilloJava::ExpectedGenRowVecElemIndRange;

#include <ExpectedGenRowVecElemInds.cpp>
using armadilloJava::ExpectedGenRowVecElemInds;

#include <ExpectedGenRowVecExp.cpp>
using armadilloJava::ExpectedGenRowVecExp;

#include <ExpectedGenRowVecGenColVec.cpp>
using armadilloJava::ExpectedGenRowVecGenColVec;

#include <ExpectedGenRowVecGenColVecNormal.cpp>
using armadilloJava::ExpectedGenRowVecGenColVecNormal;

#include <ExpectedGenRowVecGenDouble.cpp>
using armadilloJava::ExpectedGenRowVecGenDouble;

#include <ExpectedGenRowVecGenMat.cpp>
using armadilloJava::ExpectedGenRowVecGenMat;

#include <ExpectedGenRowVecGenRowVec.cpp>
using armadilloJava::ExpectedGenRowVecGenRowVec;

#include <ExpectedGenRowVecGenRowVecNormal.cpp>
using armadilloJava::ExpectedGenRowVecGenRowVecNormal;

#include <ExpectedGenRowVecMonColVec.cpp>
using armadilloJava::ExpectedGenRowVecMonColVec;

#include <ExpectedGenRowVecMonRowVec.cpp>
using armadilloJava::ExpectedGenRowVecMonRowVec;

#include <ExpectedGenRowVecNormal.cpp>
using armadilloJava::ExpectedGenRowVecNormal;

#include <ExpectedGenRowVecNumElems.cpp>
using armadilloJava::ExpectedGenRowVecNumElems;

#include <ExpectedGenRowVecNumRowsNumCols.cpp>
using armadilloJava::ExpectedGenRowVecNumRowsNumCols;

#include <ExpectedGenRowVecRowIndColInd.cpp>
using armadilloJava::ExpectedGenRowVecRowIndColInd;

#include <ExpectedGenRowVecRowIndColIndMatSize.cpp>
using armadilloJava::ExpectedGenRowVecRowIndColIndMatSize;

#include <ExpectedGenRowVecRowIndRangeColIndRange.cpp>
using armadilloJava::ExpectedGenRowVecRowIndRangeColIndRange;

#include <ExpectedGenRowVecSort.cpp>
using armadilloJava::ExpectedGenRowVecSort;

#include <ExpectedGenRowVecVecNormInt.cpp>
using armadilloJava::ExpectedGenRowVecVecNormInt;

#include <ExpectedGenRowVecVecNormString.cpp>
using armadilloJava::ExpectedGenRowVecVecNormString;

#include <ExpectedInPlaceGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVec;

#include <ExpectedInPlaceGenColVecElemInd.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemInd;

#include <ExpectedInPlaceGenColVecElemIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndGenColVec;

#include <ExpectedInPlaceGenColVecElemIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndGenDouble;

#include <ExpectedInPlaceGenColVecElemIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndGenMat;

#include <ExpectedInPlaceGenColVecElemIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndGenRowVec;

#include <ExpectedInPlaceGenColVecElemIndRange.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndRange;

#include <ExpectedInPlaceGenColVecElemIndRangeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndRangeGenColVec;

#include <ExpectedInPlaceGenColVecElemIndRangeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndRangeGenDouble;

#include <ExpectedInPlaceGenColVecElemIndRangeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndRangeGenMat;

#include <ExpectedInPlaceGenColVecElemIndRangeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndRangeGenRowVec;

#include <ExpectedInPlaceGenColVecElemIndsGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndsGenColVec;

#include <ExpectedInPlaceGenColVecElemIndsGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndsGenDouble;

#include <ExpectedInPlaceGenColVecElemIndsGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndsGenMat;

#include <ExpectedInPlaceGenColVecElemIndsGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecElemIndsGenRowVec;

#include <ExpectedInPlaceGenColVecGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecGenColVec;

#include <ExpectedInPlaceGenColVecGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenColVecGenDouble;

#include <ExpectedInPlaceGenColVecGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenColVecGenMat;

#include <ExpectedInPlaceGenColVecGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenColVecGenRowVec;

#include <ExpectedInPlaceGenColVecNumElems.cpp>
using armadilloJava::ExpectedInPlaceGenColVecNumElems;

#include <ExpectedInPlaceGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMat;

#include <ExpectedInPlaceGenMatColInd.cpp>
using armadilloJava::ExpectedInPlaceGenMatColInd;

#include <ExpectedInPlaceGenMatColIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndGenColVec;

#include <ExpectedInPlaceGenMatColIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndGenDouble;

#include <ExpectedInPlaceGenMatColIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndGenMat;

#include <ExpectedInPlaceGenMatColIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndGenRowVec;

#include <ExpectedInPlaceGenMatColIndRange.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndRange;

#include <ExpectedInPlaceGenMatColIndRangeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndRangeGenColVec;

#include <ExpectedInPlaceGenMatColIndRangeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndRangeGenDouble;

#include <ExpectedInPlaceGenMatColIndRangeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndRangeGenMat;

#include <ExpectedInPlaceGenMatColIndRangeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndRangeGenRowVec;

#include <ExpectedInPlaceGenMatColIndsGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndsGenColVec;

#include <ExpectedInPlaceGenMatColIndsGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndsGenDouble;

#include <ExpectedInPlaceGenMatColIndsGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndsGenMat;

#include <ExpectedInPlaceGenMatColIndsGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatColIndsGenRowVec;

#include <ExpectedInPlaceGenMatElemInd.cpp>
using armadilloJava::ExpectedInPlaceGenMatElemInd;

#include <ExpectedInPlaceGenMatElemIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatElemIndGenDouble;

#include <ExpectedInPlaceGenMatElemIndsGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatElemIndsGenColVec;

#include <ExpectedInPlaceGenMatElemIndsGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatElemIndsGenDouble;

#include <ExpectedInPlaceGenMatElemIndsGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatElemIndsGenMat;

#include <ExpectedInPlaceGenMatElemIndsGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatElemIndsGenRowVec;

#include <ExpectedInPlaceGenMatExtColIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtColIndGenColVec;

#include <ExpectedInPlaceGenMatExtColIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtColIndGenMat;

#include <ExpectedInPlaceGenMatExtColIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtColIndGenRowVec;

#include <ExpectedInPlaceGenMatExtColIndNumCols.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtColIndNumCols;

#include <ExpectedInPlaceGenMatExtRowIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtRowIndGenColVec;

#include <ExpectedInPlaceGenMatExtRowIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtRowIndGenMat;

#include <ExpectedInPlaceGenMatExtRowIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtRowIndGenRowVec;

#include <ExpectedInPlaceGenMatExtRowIndNumRows.cpp>
using armadilloJava::ExpectedInPlaceGenMatExtRowIndNumRows;

#include <ExpectedInPlaceGenMatGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatGenColVec;

#include <ExpectedInPlaceGenMatGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatGenDouble;

#include <ExpectedInPlaceGenMatGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatGenMat;

#include <ExpectedInPlaceGenMatGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatGenRowVec;

#include <ExpectedInPlaceGenMatNumRowsNumCols.cpp>
using armadilloJava::ExpectedInPlaceGenMatNumRowsNumCols;

#include <ExpectedInPlaceGenMatRowInd.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowInd;

#include <ExpectedInPlaceGenMatRowIndColInd.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColInd;

#include <ExpectedInPlaceGenMatRowIndColIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndGenDouble;

#include <ExpectedInPlaceGenMatRowIndColIndMatSizeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndMatSizeGenColVec;

#include <ExpectedInPlaceGenMatRowIndColIndMatSizeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndMatSizeGenDouble;

#include <ExpectedInPlaceGenMatRowIndColIndMatSizeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndMatSizeGenMat;

#include <ExpectedInPlaceGenMatRowIndColIndMatSizeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndMatSizeGenRowVec;

#include <ExpectedInPlaceGenMatRowIndColIndRangeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndRangeGenColVec;

#include <ExpectedInPlaceGenMatRowIndColIndRangeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndRangeGenDouble;

#include <ExpectedInPlaceGenMatRowIndColIndRangeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndRangeGenMat;

#include <ExpectedInPlaceGenMatRowIndColIndRangeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndColIndRangeGenRowVec;

#include <ExpectedInPlaceGenMatRowIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndGenColVec;

#include <ExpectedInPlaceGenMatRowIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndGenDouble;

#include <ExpectedInPlaceGenMatRowIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndGenMat;

#include <ExpectedInPlaceGenMatRowIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndGenRowVec;

#include <ExpectedInPlaceGenMatRowIndRange.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRange;

#include <ExpectedInPlaceGenMatRowIndRangeColIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndGenColVec;

#include <ExpectedInPlaceGenMatRowIndRangeColIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndGenDouble;

#include <ExpectedInPlaceGenMatRowIndRangeColIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndGenMat;

#include <ExpectedInPlaceGenMatRowIndRangeColIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndGenRowVec;

#include <ExpectedInPlaceGenMatRowIndRangeColIndRangeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndRangeGenColVec;

#include <ExpectedInPlaceGenMatRowIndRangeColIndRangeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndRangeGenDouble;

#include <ExpectedInPlaceGenMatRowIndRangeColIndRangeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndRangeGenMat;

#include <ExpectedInPlaceGenMatRowIndRangeColIndRangeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeColIndRangeGenRowVec;

#include <ExpectedInPlaceGenMatRowIndRangeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeGenColVec;

#include <ExpectedInPlaceGenMatRowIndRangeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeGenDouble;

#include <ExpectedInPlaceGenMatRowIndRangeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeGenMat;

#include <ExpectedInPlaceGenMatRowIndRangeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndRangeGenRowVec;

#include <ExpectedInPlaceGenMatRowIndsColIndsGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsColIndsGenColVec;

#include <ExpectedInPlaceGenMatRowIndsColIndsGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsColIndsGenDouble;

#include <ExpectedInPlaceGenMatRowIndsColIndsGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsColIndsGenMat;

#include <ExpectedInPlaceGenMatRowIndsColIndsGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsColIndsGenRowVec;

#include <ExpectedInPlaceGenMatRowIndsGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsGenColVec;

#include <ExpectedInPlaceGenMatRowIndsGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsGenDouble;

#include <ExpectedInPlaceGenMatRowIndsGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsGenMat;

#include <ExpectedInPlaceGenMatRowIndsGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenMatRowIndsGenRowVec;

#include <ExpectedInPlaceGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVec;

#include <ExpectedInPlaceGenRowVecElemInd.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemInd;

#include <ExpectedInPlaceGenRowVecElemIndGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndGenColVec;

#include <ExpectedInPlaceGenRowVecElemIndGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndGenDouble;

#include <ExpectedInPlaceGenRowVecElemIndGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndGenMat;

#include <ExpectedInPlaceGenRowVecElemIndGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndGenRowVec;

#include <ExpectedInPlaceGenRowVecElemIndRange.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndRange;

#include <ExpectedInPlaceGenRowVecElemIndRangeGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndRangeGenColVec;

#include <ExpectedInPlaceGenRowVecElemIndRangeGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndRangeGenDouble;

#include <ExpectedInPlaceGenRowVecElemIndRangeGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndRangeGenMat;

#include <ExpectedInPlaceGenRowVecElemIndRangeGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndRangeGenRowVec;

#include <ExpectedInPlaceGenRowVecElemIndsGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndsGenColVec;

#include <ExpectedInPlaceGenRowVecElemIndsGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndsGenDouble;

#include <ExpectedInPlaceGenRowVecElemIndsGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndsGenMat;

#include <ExpectedInPlaceGenRowVecElemIndsGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecElemIndsGenRowVec;

#include <ExpectedInPlaceGenRowVecGenColVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecGenColVec;

#include <ExpectedInPlaceGenRowVecGenDouble.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecGenDouble;

#include <ExpectedInPlaceGenRowVecGenMat.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecGenMat;

#include <ExpectedInPlaceGenRowVecGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceGenRowVecGenRowVec;

#include <ExpectedInPlaceRandomGenColVec.cpp>
using armadilloJava::ExpectedInPlaceRandomGenColVec;

#include <ExpectedInPlaceRandomGenColVecNumElems.cpp>
using armadilloJava::ExpectedInPlaceRandomGenColVecNumElems;

#include <ExpectedInPlaceRandomGenMat.cpp>
using armadilloJava::ExpectedInPlaceRandomGenMat;

#include <ExpectedInPlaceRandomGenMatNumRowsNumCols.cpp>
using armadilloJava::ExpectedInPlaceRandomGenMatNumRowsNumCols;

#include <ExpectedInPlaceRandomGenRowVec.cpp>
using armadilloJava::ExpectedInPlaceRandomGenRowVec;

#include <ExpectedInPlaceRandomGenRowVecNumElems.cpp>
using armadilloJava::ExpectedInPlaceRandomGenRowVecNumElems;

#include <ExpectedInvMat.cpp>
using armadilloJava::ExpectedInvMat;

#include <ExpectedLogicColVec.cpp>
using armadilloJava::ExpectedLogicColVec;

#include <ExpectedLogicColVecNumElems.cpp>
using armadilloJava::ExpectedLogicColVecNumElems;

#include <ExpectedLogicMat.cpp>
using armadilloJava::ExpectedLogicMat;

#include <ExpectedLogicMatDim.cpp>
using armadilloJava::ExpectedLogicMatDim;

#include <ExpectedLogicMatNumElems.cpp>
using armadilloJava::ExpectedLogicMatNumElems;

#include <ExpectedLogicMatNumElemsSearch.cpp>
using armadilloJava::ExpectedLogicMatNumElemsSearch;

#include <ExpectedLogicRowVec.cpp>
using armadilloJava::ExpectedLogicRowVec;

#include <ExpectedLogicRowVecNumElems.cpp>
using armadilloJava::ExpectedLogicRowVecNumElems;

#include <ExpectedNumElems.cpp>
using armadilloJava::ExpectedNumElems;

#include <ExpectedNumRowsNumCols.cpp>
using armadilloJava::ExpectedNumRowsNumCols;

#include <ExpectedOOColVec.cpp>
using armadilloJava::ExpectedOOColVec;

#include <ExpectedOOMat.cpp>
using armadilloJava::ExpectedOOMat;

#include <ExpectedOORowVec.cpp>
using armadilloJava::ExpectedOORowVec;

#include <ExpectedRandomGenColVec.cpp>
using armadilloJava::ExpectedRandomGenColVec;

#include <ExpectedRandomGenMat.cpp>
using armadilloJava::ExpectedRandomGenMat;

#include <ExpectedRandomGenMatDim.cpp>
using armadilloJava::ExpectedRandomGenMatDim;

#include <ExpectedRandomGenRowVec.cpp>
using armadilloJava::ExpectedRandomGenRowVec;

#include <ExpectedRandomNumElems.cpp>
using armadilloJava::ExpectedRandomNumElems;

#include <ExpectedRandomNumElemsDistrParam.cpp>
using armadilloJava::ExpectedRandomNumElemsDistrParam;

#include <ExpectedRandomNumRowsNumCols.cpp>
using armadilloJava::ExpectedRandomNumRowsNumCols;

#include <ExpectedRandomNumRowsNumColsDistrParam.cpp>
using armadilloJava::ExpectedRandomNumRowsNumColsDistrParam;

#include <ExpectedSquMat.cpp>
using armadilloJava::ExpectedSquMat;

#include <ExpectedSquMatSquMatGenMat.cpp>
using armadilloJava::ExpectedSquMatSquMatGenMat;

#include <ExpectedSymMat.cpp>
using armadilloJava::ExpectedSymMat;

#include <ExpectedSymPDMat.cpp>
using armadilloJava::ExpectedSymPDMat;

int main() {
  ofstream logfile("./expected.log");
  cout.rdbuf(logfile.rdbuf());
  set_stream_err1(logfile);
  set_stream_err2(logfile);

  arma_rng::set_seed(123456789);

  /**
   * Add comments to all classes below, before pushing a commit to avoid unnecessary conflicts.
   */

//  ExpectedDatum();
//  ExpectedElemIndFill();
//  ExpectedGenColVec();
//  ExpectedGenColVecElemInd();
//  ExpectedGenColVecElemIndRange();
//  ExpectedGenColVecElemInds();
//  ExpectedGenColVecExp();
//  ExpectedGenColVecGenColVec();
//  ExpectedGenColVecGenColVecNormal();
//  ExpectedGenColVecGenDouble();
//  ExpectedGenColVecGenMat();
//  ExpectedGenColVecGenRowVec();
//  ExpectedGenColVecGenRowVecNormal();
//  ExpectedGenColVecMonColVec();
//  ExpectedGenColVecMonRowVec();
//  ExpectedGenColVecNormal();
//  ExpectedGenColVecNumElems();
//  ExpectedGenColVecNumRowsNumCols();
//  ExpectedGenColVecRowIndColInd();
//  ExpectedGenColVecRowIndColIndMatSize();
//  ExpectedGenColVecRowIndRangeColIndRange();
//  ExpectedGenColVecSort();
//  ExpectedGenColVecVecNormInt();
//  ExpectedGenColVecVecNormString();
//  ExpectedGenDouble();
//  ExpectedGenDoubleGenDouble();
//  ExpectedGenDoubleGenDoubleNumElems();
//  ExpectedGenMat();
//  ExpectedGenMatColInd();
//  ExpectedGenMatColIndRange();
//  ExpectedGenMatColInds();
//  ExpectedGenMatDim();
//  ExpectedGenMatElemInd();
//  ExpectedGenMatElemIndRange();
//  ExpectedGenMatElemInds();
//  ExpectedGenMatExp();
//  ExpectedGenMatGenColVec();
//  ExpectedGenMatGenDouble();
//  ExpectedGenMatGenMat();
//  ExpectedGenMatGenMatNormal();
//  ExpectedGenMatGenRowVec();
//  ExpectedGenMatMatNormInt();
//  ExpectedGenMatMatNormString();
//  ExpectedGenMatMonColVec();
//  ExpectedGenMatMonColVecDim();
//  ExpectedGenMatMonRowVec();
//  ExpectedGenMatMonRowVecDim();
//  ExpectedGenMatNormal();
//  ExpectedGenMatNormalDim();
//  ExpectedGenMatNumElems();
//  ExpectedGenMatNumElemsDim();
//  ExpectedGenMatNumRowsNumCols();
//  ExpectedGenMatRowInd();
//  ExpectedGenMatRowIndColInd();
//  ExpectedGenMatRowIndColIndMatSize();
//  ExpectedGenMatRowIndColIndRange();
//  ExpectedGenMatRowIndRange();
//  ExpectedGenMatRowIndRangeColInd();
//  ExpectedGenMatRowIndRangeColIndRange();
//  ExpectedGenMatRowInds();
//  ExpectedGenMatRowIndsColInds();
//  ExpectedGenMatSinValSel();
//  ExpectedGenMatSinValTol();
//  ExpectedGenMatSort();
//  ExpectedGenMatSortDim();
//  ExpectedGenMatVecNormInt();
//  ExpectedGenRowVec();
//  ExpectedGenRowVecElemInd();
//  ExpectedGenRowVecElemIndRange();
//  ExpectedGenRowVecElemInds();
//  ExpectedGenRowVecExp();
//  ExpectedGenRowVecGenColVec();
//  ExpectedGenRowVecGenColVecNormal();
//  ExpectedGenRowVecGenDouble();
//  ExpectedGenRowVecGenMat();
//  ExpectedGenRowVecGenRowVec();
//  ExpectedGenRowVecGenRowVecNormal();
//  ExpectedGenRowVecMonColVec();
//  ExpectedGenRowVecMonRowVec();
//  ExpectedGenRowVecNormal();
//  ExpectedGenRowVecNumElems();
//  ExpectedGenRowVecNumRowsNumCols();
//  ExpectedGenRowVecRowIndColInd();
//  ExpectedGenRowVecRowIndColIndMatSize();
//  ExpectedGenRowVecRowIndRangeColIndRange();
//  ExpectedGenRowVecSort();
//  ExpectedGenRowVecVecNormInt();
//  ExpectedGenRowVecVecNormString();
//  ExpectedInPlaceGenColVec();
//  ExpectedInPlaceGenColVecElemInd();
//  ExpectedInPlaceGenColVecElemIndGenColVec();
//  ExpectedInPlaceGenColVecElemIndGenDouble();
//  ExpectedInPlaceGenColVecElemIndGenMat();
//  ExpectedInPlaceGenColVecElemIndGenRowVec();
//  ExpectedInPlaceGenColVecElemIndRange();
//  ExpectedInPlaceGenColVecElemIndRangeGenColVec();
//  ExpectedInPlaceGenColVecElemIndRangeGenDouble();
//  ExpectedInPlaceGenColVecElemIndRangeGenMat();
//  ExpectedInPlaceGenColVecElemIndRangeGenRowVec();
//  ExpectedInPlaceGenColVecElemIndsGenColVec();
//  ExpectedInPlaceGenColVecElemIndsGenDouble();
//  ExpectedInPlaceGenColVecElemIndsGenMat();
//  ExpectedInPlaceGenColVecElemIndsGenRowVec();
//  ExpectedInPlaceGenColVecGenColVec();
//  ExpectedInPlaceGenColVecGenDouble();
//  ExpectedInPlaceGenColVecGenMat();
//  ExpectedInPlaceGenColVecGenRowVec();
//  ExpectedInPlaceGenColVecNumElems();
//  ExpectedInPlaceGenMat();
//  ExpectedInPlaceGenMatColInd();
//  ExpectedInPlaceGenMatColIndGenColVec();
//  ExpectedInPlaceGenMatColIndGenDouble();
//  ExpectedInPlaceGenMatColIndGenMat();
//  ExpectedInPlaceGenMatColIndGenRowVec();
//  ExpectedInPlaceGenMatColIndRange();
//  ExpectedInPlaceGenMatColIndRangeGenColVec();
//  ExpectedInPlaceGenMatColIndRangeGenDouble();
//  ExpectedInPlaceGenMatColIndRangeGenMat();
//  ExpectedInPlaceGenMatColIndRangeGenRowVec();
//  ExpectedInPlaceGenMatColIndsGenColVec();
//  ExpectedInPlaceGenMatColIndsGenDouble();
//  ExpectedInPlaceGenMatColIndsGenMat();
//  ExpectedInPlaceGenMatColIndsGenRowVec();
//  ExpectedInPlaceGenMatElemInd();
//  ExpectedInPlaceGenMatElemIndGenDouble();
//  ExpectedInPlaceGenMatElemIndsGenColVec();
//  ExpectedInPlaceGenMatElemIndsGenDouble();
//  ExpectedInPlaceGenMatElemIndsGenMat();
//  ExpectedInPlaceGenMatElemIndsGenRowVec();
//  ExpectedInPlaceGenMatExtColIndGenColVec();
//  ExpectedInPlaceGenMatExtColIndGenMat();
//  ExpectedInPlaceGenMatExtColIndGenRowVec();
//  ExpectedInPlaceGenMatExtColIndNumCols();
//  ExpectedInPlaceGenMatExtRowIndGenColVec();
//  ExpectedInPlaceGenMatExtRowIndGenMat();
//  ExpectedInPlaceGenMatExtRowIndGenRowVec();
//  ExpectedInPlaceGenMatExtRowIndNumRows();
//  ExpectedInPlaceGenMatGenColVec();
//  ExpectedInPlaceGenMatGenDouble();
//  ExpectedInPlaceGenMatGenMat();
//  ExpectedInPlaceGenMatGenRowVec();
//  ExpectedInPlaceGenMatNumRowsNumCols();
//  ExpectedInPlaceGenMatRowInd();
//  ExpectedInPlaceGenMatRowIndColInd();
//  ExpectedInPlaceGenMatRowIndColIndGenDouble();
//  ExpectedInPlaceGenMatRowIndColIndMatSizeGenColVec();
//  ExpectedInPlaceGenMatRowIndColIndMatSizeGenDouble();
//  ExpectedInPlaceGenMatRowIndColIndMatSizeGenMat();
//  ExpectedInPlaceGenMatRowIndColIndMatSizeGenRowVec();
//  ExpectedInPlaceGenMatRowIndColIndRangeGenColVec();
//  ExpectedInPlaceGenMatRowIndColIndRangeGenDouble();
//  ExpectedInPlaceGenMatRowIndColIndRangeGenMat();
//  ExpectedInPlaceGenMatRowIndColIndRangeGenRowVec();
//  ExpectedInPlaceGenMatRowIndGenColVec();
//  ExpectedInPlaceGenMatRowIndGenDouble();
//  ExpectedInPlaceGenMatRowIndGenMat();
//  ExpectedInPlaceGenMatRowIndGenRowVec();
//  ExpectedInPlaceGenMatRowIndRange();
//  ExpectedInPlaceGenMatRowIndRangeColIndGenColVec();
//  ExpectedInPlaceGenMatRowIndRangeColIndGenDouble();
//  ExpectedInPlaceGenMatRowIndRangeColIndGenMat();
//  ExpectedInPlaceGenMatRowIndRangeColIndGenRowVec();
//  ExpectedInPlaceGenMatRowIndRangeColIndRangeGenColVec();
//  ExpectedInPlaceGenMatRowIndRangeColIndRangeGenDouble();
//  ExpectedInPlaceGenMatRowIndRangeColIndRangeGenMat();
//  ExpectedInPlaceGenMatRowIndRangeColIndRangeGenRowVec();
//  ExpectedInPlaceGenMatRowIndRangeGenColVec();
//  ExpectedInPlaceGenMatRowIndRangeGenDouble();
//  ExpectedInPlaceGenMatRowIndRangeGenMat();
//  ExpectedInPlaceGenMatRowIndRangeGenRowVec();
//  ExpectedInPlaceGenMatRowIndsColIndsGenColVec();
//  ExpectedInPlaceGenMatRowIndsColIndsGenDouble();
//  ExpectedInPlaceGenMatRowIndsColIndsGenMat();
//  ExpectedInPlaceGenMatRowIndsColIndsGenRowVec();
//  ExpectedInPlaceGenMatRowIndsGenColVec();
//  ExpectedInPlaceGenMatRowIndsGenDouble();
//  ExpectedInPlaceGenMatRowIndsGenMat();
//  ExpectedInPlaceGenMatRowIndsGenRowVec();
//  ExpectedInPlaceGenRowVec();
//  ExpectedInPlaceGenRowVecElemInd();
//  ExpectedInPlaceGenRowVecElemIndGenColVec();
//  ExpectedInPlaceGenRowVecElemIndGenDouble();
//  ExpectedInPlaceGenRowVecElemIndGenMat();
//  ExpectedInPlaceGenRowVecElemIndGenRowVec();
//  ExpectedInPlaceGenRowVecElemIndRange();
//  ExpectedInPlaceGenRowVecElemIndRangeGenColVec();
//  ExpectedInPlaceGenRowVecElemIndRangeGenDouble();
//  ExpectedInPlaceGenRowVecElemIndRangeGenMat();
//  ExpectedInPlaceGenRowVecElemIndRangeGenRowVec();
//  ExpectedInPlaceGenRowVecElemIndsGenColVec();
//  ExpectedInPlaceGenRowVecElemIndsGenDouble();
//  ExpectedInPlaceGenRowVecElemIndsGenMat();
//  ExpectedInPlaceGenRowVecElemIndsGenRowVec();
//  ExpectedInPlaceGenRowVecGenColVec();
//  ExpectedInPlaceGenRowVecGenDouble();
//  ExpectedInPlaceGenRowVecGenMat();
//  ExpectedInPlaceGenRowVecGenRowVec();
//  ExpectedInPlaceRandomGenColVec();
//  ExpectedInPlaceRandomGenColVecNumElems();
//  ExpectedInPlaceRandomGenMat();
//  ExpectedInPlaceRandomGenMatNumRowsNumCols();
//  ExpectedInPlaceRandomGenRowVec();
//  ExpectedInPlaceRandomGenRowVecNumElems();
//  ExpectedInvMat();
//  ExpectedLogicColVec();
//  ExpectedLogicColVecNumElems();
//  ExpectedLogicMat();
//  ExpectedLogicMatDim();
//  ExpectedLogicMatNumElems();
//  ExpectedLogicMatNumElemsSearch();
//  ExpectedLogicRowVec();
//  ExpectedLogicRowVecNumElems();
//  ExpectedNumElems();
//  ExpectedNumRowsNumCols();
//  ExpectedOOColVec();
//  ExpectedOOMat();
//  ExpectedOORowVec();
//  ExpectedRandomGenColVec();
//  ExpectedRandomGenMat();
//  ExpectedRandomGenMatDim();
//  ExpectedRandomGenRowVec();
//  ExpectedRandomNumElems();
//  ExpectedRandomNumElemsDistrParam();
//  ExpectedRandomNumRowsNumCols();
//  ExpectedRandomNumRowsNumColsDistrParam();
//  ExpectedSquMat();
//  ExpectedSquMatSquMatGenMat();
//  ExpectedSymMat();
//  ExpectedSymPDMat();

  return EXIT_SUCCESS;
}


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE vector_sort

#include <algorithm>
#include <boost/predef.h>
#include <random>

#if BOOST_COMP_GNUC
extern "C"
{
#    include "quadmath.h"
}
#endif

#include <boost/multiprecision/cpp_int.hpp>
#if BOOST_COMP_GNUC
#    include <boost/multiprecision/float128.hpp>
#endif
#include <boost/test/unit_test.hpp>
#include "vector/vector.hpp"

BOOST_AUTO_TEST_CASE(test_vector_sort_sort_1)
{
    std::vector<uint64_t> unordered(50);
    std::iota(unordered.begin(), unordered.end(), 0);

    auto ordered = unordered;
    auto rng = std::default_random_engine {};
    std::shuffle(std::begin(unordered), std::end(unordered), rng);
    // BOOST_FAIL( "Test is not ready yet" );
    BOOST_REQUIRE_MESSAGE(ordered != unordered, "ordered == unordered"
                                                    << " instead: "
                                                    << "ordered != unordered");
    my::vector::sort_sort<uint64_t>(unordered);

    BOOST_REQUIRE_EQUAL_COLLECTIONS(unordered.begin(), unordered.end(), ordered.begin(), ordered.end());
}

BOOST_AUTO_TEST_CASE(test_vector_sort_sort_2)
{
    std::vector<uint64_t> unordered(200);
    std::iota(unordered.begin(), unordered.end(), 0);

    auto ordered = unordered;
    auto rng = std::default_random_engine {};
    std::shuffle(std::begin(unordered), std::end(unordered), rng);
    BOOST_REQUIRE_MESSAGE(ordered != unordered, "ordered == unordered"
                                                    << " instead: "
                                                    << "ordered != unordered");
    my::vector::sort_sort<uint64_t>(unordered);

    BOOST_REQUIRE_EQUAL_COLLECTIONS(unordered.begin(), unordered.end(), ordered.begin(), ordered.end());
}


/**
 * Copyright (c) 2015-2019 Przemysław Dobrowolski
 *
 * This file is part of the Configuration Space Library (libcs2), a library
 * for creating configuration spaces of various motion planning problems.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "renderview.h"
#include "renderviewarcballcamera.h"
#include "renderviewflycamera.h"
#include "renderviewautocamera.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
#include <QTextStream>
#include <QFile>
#include <QImage>
#include <boost/scoped_array.hpp>
#include <cassert>
#include <cmath>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    m_currentChanged(false),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // setup
    if (true)
    {
        QGLFormat fmt;
        fmt.setSamples(4);
        fmt.setSampleBuffers(true);
        QGLFormat::setDefaultFormat(fmt);
    }

    m_rv = new RenderView();

    m_rv->setCaption("cspace");
    m_rv->enableViewModeOption(ViewMode::Culling);

    ui->widgetView->layout()->addWidget(m_rv);

    // update slider information
    updateSliderInformation();

    // update predicate predicate
    updatePredicateInformation();

    // window title
    updateWindowTitle();

    // force no-changes
    m_currentChanged = false;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::updatePredicateInformation()
{
    // changed
    m_currentChanged = true;
    updateWindowTitle();

    // predicate tt
    struct cs2_predtt3f_s tt =
        {
            { sliderToParamValue(ui->verticalSliderKX), sliderToParamValue(ui->verticalSliderKY), sliderToParamValue(ui->verticalSliderKZ) },
            { sliderToParamValue(ui->verticalSliderLX), sliderToParamValue(ui->verticalSliderLY), sliderToParamValue(ui->verticalSliderLZ) },
            { sliderToParamValue(ui->verticalSliderMX), sliderToParamValue(ui->verticalSliderMY), sliderToParamValue(ui->verticalSliderMZ) },
            { sliderToParamValue(ui->verticalSliderAX), sliderToParamValue(ui->verticalSliderAY), sliderToParamValue(ui->verticalSliderAZ) },
            { sliderToParamValue(ui->verticalSliderBX), sliderToParamValue(ui->verticalSliderBY), sliderToParamValue(ui->verticalSliderBZ) },
            { sliderToParamValue(ui->verticalSliderCX), sliderToParamValue(ui->verticalSliderCY), sliderToParamValue(ui->verticalSliderCZ) }
        };

    // decompose tt->s
    struct cs2_predttdecomp3f_s ttd;
    cs2_predtt3f_decomp(&ttd, &tt);

    // visual
    m_rv->removeAllObjects();

    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 3; ++j)
        {
            struct cs2_preds3f_s *s = &ttd.s[i][j];
            struct cs2_predg3f_s g;

            cs2_predg3f_from_preds3f(&g, s);

            // param g
            struct cs2_predgparam3f_s param;
            cs2_predg3f_param(&param, &g);

            // only 2-dimensional
            if (cs2_predgparamtype3f_dim(param.t) == 2)
            {
                TriangleListPtr trianglesFront(new TriangleList());
                TriangleListPtr trianglesBack(new TriangleList());

                if (ui->actionAutoMesh->isChecked())
                    meshing::meshSurfaceAdaptive(trianglesFront, trianglesBack, &param, 0.1, 0.5, 10);
                else
                    meshing::meshSurfaceSimple(trianglesFront, trianglesBack, &param, 0.01);

                filterTriangles(trianglesFront);
                filterTriangles(trianglesBack);

                const QColor nepalColor(142, 171, 193);

                m_rv->addTriangleList(trianglesFront, nepalColor);
                m_rv->addTriangleList(trianglesBack, nepalColor);
            }
        }
    }
}

double MainWindow::sliderToParamValue(QSlider *slider)
{
    return sliderValueToParamValue(slider->value());
}

double MainWindow::sliderValueToParamValue(double value)
{
    return 0.01 * (value - 300) / 3.0;
}

void MainWindow::formatSliderValue(QLabel *label, double value)
{
    label->setText(QString::number(sliderValueToParamValue(value), 'f', 2));
}

void MainWindow::updateSliderInformation()
{
    formatSliderValue(ui->labelSliderKX, ui->verticalSliderKX->value());
    formatSliderValue(ui->labelSliderKY, ui->verticalSliderKY->value());
    formatSliderValue(ui->labelSliderKZ, ui->verticalSliderKZ->value());

    formatSliderValue(ui->labelSliderLX, ui->verticalSliderLX->value());
    formatSliderValue(ui->labelSliderLY, ui->verticalSliderLY->value());
    formatSliderValue(ui->labelSliderLZ, ui->verticalSliderLZ->value());

    formatSliderValue(ui->labelSliderMX, ui->verticalSliderMX->value());
    formatSliderValue(ui->labelSliderMY, ui->verticalSliderMY->value());
    formatSliderValue(ui->labelSliderMZ, ui->verticalSliderMZ->value());

    formatSliderValue(ui->labelSliderAX, ui->verticalSliderAX->value());
    formatSliderValue(ui->labelSliderAY, ui->verticalSliderAY->value());
    formatSliderValue(ui->labelSliderAZ, ui->verticalSliderAZ->value());

    formatSliderValue(ui->labelSliderBX, ui->verticalSliderBX->value());
    formatSliderValue(ui->labelSliderBY, ui->verticalSliderBY->value());
    formatSliderValue(ui->labelSliderBZ, ui->verticalSliderBZ->value());

    formatSliderValue(ui->labelSliderCX, ui->verticalSliderCX->value());
    formatSliderValue(ui->labelSliderCY, ui->verticalSliderCY->value());
    formatSliderValue(ui->labelSliderCZ, ui->verticalSliderCZ->value());
}

QString MainWindow::formatVector(const struct cs2_vec3f_s *v)
{
    return "[" + QString::number(v->x, 'f', 2) + ", " + QString::number(v->y, 'f', 2) + ", " + QString::number(v->z, 'f', 2) + "]";
}

QString MainWindow::formatVector(const struct cs2_vec4f_s *v)
{
    return "[" + QString::number(v->x, 'f', 2) + ", " + QString::number(v->y, 'f', 2) + ", " + QString::number(v->z, 'f', 2) + ", " + QString::number(v->w, 'f', 2) + "]";
}

bool MainWindow::handleUnsavedChanges()
{
    switch (QMessageBox::question(this, tr("Unsaved changes"), tr("Save changes to file?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel))
    {
        case QMessageBox::Yes:
            if (!m_currentFile.isEmpty())
                return saveCurrentFile();
            else
                return saveNewFile();

        case QMessageBox::No:
            return true;

        case QMessageBox::Cancel:
            return false;

    default:
        assert(0);
    }
}

bool MainWindow::saveCurrentFile()
{
    // changes
    m_currentChanged = false;
    updateWindowTitle();

    // save
    QFile out(m_currentFile);

    if (out.open(QFile::WriteOnly))
    {
        //writer
        {
            QTextStream stream(&out);

            stream << ui->verticalSliderKX->value() << " ";
            stream << ui->verticalSliderKY->value() << " ";
            stream << ui->verticalSliderKZ->value();
            stream << "\r\n";
            stream << ui->verticalSliderLX->value() << " ";
            stream << ui->verticalSliderLY->value() << " ";
            stream << ui->verticalSliderLZ->value();
            stream << "\r\n";
            stream << ui->verticalSliderMX->value() << " ";
            stream << ui->verticalSliderMY->value() << " ";
            stream << ui->verticalSliderMZ->value();
            stream << "\r\n";
            stream << ui->verticalSliderAX->value() << " ";
            stream << ui->verticalSliderAY->value() << " ";
            stream << ui->verticalSliderAZ->value();
            stream << "\r\n";
            stream << ui->verticalSliderBX->value() << " ";
            stream << ui->verticalSliderBY->value() << " ";
            stream << ui->verticalSliderBZ->value();
            stream << "\r\n";
            stream << ui->verticalSliderCX->value() << " ";
            stream << ui->verticalSliderCY->value() << " ";
            stream << ui->verticalSliderCZ->value();
            stream << "\r\n";
        }

        out.close();
    }
    else
    {
        (void)QMessageBox::warning(this, tr("Save file"), tr("Failed to write: ") + m_currentFile, QMessageBox::Ok);
        return false;
    }

    return true;
}

bool MainWindow::saveNewFile()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save as"), QString(), QString("*.tri"));

    if (fileName.isEmpty())
        return false;

    if (!fileName.endsWith(".tri"))
        fileName += ".tri";

    m_currentFile = fileName;
    return saveCurrentFile();
}

void MainWindow::updateWindowTitle()
{
    QString fileName;

    if (m_currentFile.isEmpty())
        fileName = "unnamed.tri";
    else
    {
        QFileInfo fileInfo(m_currentFile);
        fileName = fileInfo.fileName();
    }

    setWindowTitle(fileName + ": vis" + (m_currentChanged ? " *" : ""));
}

void MainWindow::filterTriangles(TriangleListPtr triangles)
{
    TriangleListPtr filteredTriangles(new TriangleList());

    double cutoffDistance = ui->doubleSpinBoxCutoffDistance->value();

    for (TriangleList::const_iterator it = triangles->begin(); it != triangles->end(); ++it)
    {
        const Triangle &triangle = *it;

        if (triangle.vertex(0).length() < cutoffDistance || triangle.vertex(1).length() < cutoffDistance || triangle.vertex(2).length() < cutoffDistance)
            filteredTriangles->push_back(triangle);
    }

    triangles->swap(*filteredTriangles);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (!m_currentChanged)
        return;

    if (!handleUnsavedChanges())
    {
        event->ignore();
        return;
    }
}

void MainWindow::on_actionArcballCamera_triggered()
{
    m_rv->setRenderViewCamera(new RenderViewArcBallCamera());

    ui->actionArcballCamera->setChecked(true);
    ui->actionFreeCamera->setChecked(false);
    ui->actionAutoCamera->setChecked(false);
}

void MainWindow::on_actionFreeCamera_triggered()
{
    m_rv->setRenderViewCamera(new RenderViewFlyCamera());

    ui->actionArcballCamera->setChecked(false);
    ui->actionFreeCamera->setChecked(true);
    ui->actionAutoCamera->setChecked(false);
}

void MainWindow::on_actionAutoCamera_triggered()
{
    m_rv->setRenderViewCamera(new RenderViewAutoCamera());

    ui->actionArcballCamera->setChecked(false);
    ui->actionFreeCamera->setChecked(false);
    ui->actionAutoCamera->setChecked(true);
}

void MainWindow::on_verticalSliderKX_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderKX, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderKY_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderKY, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderKZ_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderKZ, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderLX_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderLX, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderLY_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderLY, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderLZ_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderLZ, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderMX_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderMX, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderMY_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderMY, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderMZ_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderMZ, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderAX_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderAX, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderAY_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderAY, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderAZ_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderAZ, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderBX_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderBX, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderBY_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderBY, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderBZ_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderBZ, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderCX_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderCX, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderCY_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderCY, value);
    updatePredicateInformation();
}

void MainWindow::on_verticalSliderCZ_valueChanged(int value)
{
    formatSliderValue(ui->labelSliderCZ, value);
    updatePredicateInformation();
}

void MainWindow::on_labelZeroK_linkActivated(const QString &link)
{
    Q_UNUSED(link);

    ui->verticalSliderKX->setValue(300);
    ui->verticalSliderKY->setValue(300);
    ui->verticalSliderKZ->setValue(300);
}

void MainWindow::on_labelZeroL_linkActivated(const QString &link)
{
    Q_UNUSED(link);

    ui->verticalSliderLX->setValue(300);
    ui->verticalSliderLY->setValue(300);
    ui->verticalSliderLZ->setValue(300);
}

void MainWindow::on_labelZeroM_linkActivated(const QString &link)
{
    Q_UNUSED(link);

    ui->verticalSliderMX->setValue(300);
    ui->verticalSliderMY->setValue(300);
    ui->verticalSliderMZ->setValue(300);
}

void MainWindow::on_labelZeroA_linkActivated(const QString &link)
{
    Q_UNUSED(link);

    ui->verticalSliderAX->setValue(300);
    ui->verticalSliderAY->setValue(300);
    ui->verticalSliderAZ->setValue(300);
}

void MainWindow::on_labelZeroB_linkActivated(const QString &link)
{
    Q_UNUSED(link);

    ui->verticalSliderBX->setValue(300);
    ui->verticalSliderBY->setValue(300);
    ui->verticalSliderBZ->setValue(300);
}

void MainWindow::on_labelZeroC_linkActivated(const QString &link)
{
    Q_UNUSED(link);

    ui->verticalSliderCX->setValue(300);
    ui->verticalSliderCY->setValue(300);
    ui->verticalSliderCZ->setValue(300);
}

void MainWindow::on_actionWireframe_triggered()
{
    m_rv->setViewModeOption(ViewMode::Wireframe, ui->actionWireframe->isChecked());
}

void MainWindow::on_actionQuit_triggered()
{
    if (!m_currentChanged)
    {
        emit close();
        return;
    }

    if (!handleUnsavedChanges())
        return;

    emit close();
}

void MainWindow::on_actionOpen_triggered()
{
    if (m_currentChanged && !handleUnsavedChanges())
        return;

    QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), QString(), tr("*.tri"));

    if (fileName.isEmpty())
        return;

    QFile file(fileName);

    if (file.open(QFile::ReadOnly))
    {
        // reader
        {
            QTextStream stream(&file);

            int kx, ky, kz;
            stream >> kx >> ky >> kz;

            int lx, ly, lz;
            stream >> lx >> ly >> lz;

            int mx, my, mz;
            stream >> mx >> my >> mz;

            int ax, ay, az;
            stream >> ax >> ay >> az;

            int bx, by, bz;
            stream >> bx >> by >> bz;

            int cx, cy, cz;
            stream >> cx >> cy >> cz;

            if (stream.status() != QTextStream::Ok)
            {
                (void)QMessageBox::warning(this, tr("Open file"), tr("Failed to parse: ") + m_currentFile, QMessageBox::Ok);
                return;
            }

            ui->verticalSliderKX->setValue(kx);
            ui->verticalSliderKY->setValue(ky);
            ui->verticalSliderKZ->setValue(kz);

            ui->verticalSliderLX->setValue(lx);
            ui->verticalSliderLY->setValue(ly);
            ui->verticalSliderLZ->setValue(lz);

            ui->verticalSliderMX->setValue(mx);
            ui->verticalSliderMY->setValue(my);
            ui->verticalSliderMZ->setValue(mz);

            ui->verticalSliderAX->setValue(ax);
            ui->verticalSliderAY->setValue(ay);
            ui->verticalSliderAZ->setValue(az);

            ui->verticalSliderBX->setValue(bx);
            ui->verticalSliderBY->setValue(by);
            ui->verticalSliderBZ->setValue(bz);

            ui->verticalSliderCX->setValue(cx);
            ui->verticalSliderCY->setValue(cy);
            ui->verticalSliderCZ->setValue(cz);
        }

        file.close();
    }
    else
    {
        (void)QMessageBox::warning(this, tr("Open file"), tr("Failed to open: ") + m_currentFile, QMessageBox::Ok);
        return;
    }

    m_currentFile = fileName;
    m_currentChanged = false;
    updateWindowTitle();
}

void MainWindow::on_actionSave_triggered()
{
    if (m_currentChanged)
    {
        if (!m_currentFile.isEmpty())
            (void)saveCurrentFile();
        else
            (void)saveNewFile();
    }
}

void MainWindow::on_actionSaveAs_triggered()
{
    (void)saveNewFile();
}

void MainWindow::on_actionAutoMesh_triggered()
{
    updatePredicateInformation();
}

void MainWindow::on_actionTakeScreenshot_triggered()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save current frame buffer as"), QString(), QString("*.png"));

    if (fileName.isEmpty())
        return;

    if (!fileName.endsWith(".png"))
        fileName += ".png";

    QImage img = m_rv->grabFrameBuffer();

    if (!img.save(fileName, 0, 100))
    {
        (void)QMessageBox::warning(this, tr("Save current frame buffer file"), tr("Failed to save frame buffer"), QMessageBox::Ok);
        return;
    }
}

void MainWindow::on_actionModelOnlyView_triggered()
{
    m_rv->setViewModeOption(ViewMode::ModelOnly, ui->actionModelOnlyView->isChecked());
}

void MainWindow::on_actionOutlines_triggered()
{
    m_rv->setViewModeOption(ViewMode::Outlines, ui->actionOutlines->isChecked());
}

void MainWindow::on_actionNormals_triggered()
{
    m_rv->setViewModeOption(ViewMode::Normals, ui->actionNormals->isChecked());
}

void MainWindow::on_doubleSpinBoxCutoffDistance_valueChanged(double value)
{
    Q_UNUSED(value);
    updatePredicateInformation();
}


#ifndef TOOLS_HPP
#define TOOLS_HPP

#include <set>
#include <map>
#include <cmath>
#include <string>
#include <memory>
#include <vector>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/predicate.hpp>

namespace Anaquin
{
    typedef std::string Tok;
    typedef std::vector<Tok> Toks;

    template <typename T> static void split(const Tok &x, const Tok &d, T &r)
    {
        r.clear();
        boost::split(r, x, boost::is_any_of(d));
    }

    inline Tok join(const Toks &x, const std::string &d)
    {
        return boost::algorithm::join(x, d);
    }

    inline bool isEnded(const Tok &x, const Tok &y)
    {
        return boost::algorithm::ends_with(x, y);
    }

    // Eg: "C_12_D" to "C_12"
    inline Tok first(const Tok &x, const Tok &d)
    {
        Toks toks;
        toks.clear();
        split(x, d, toks);
        return toks.front();
    }

    // Eg: "C_12_D" to "D"
    inline Tok last(const Tok &x, const Tok &d)
    {
        Toks toks;
        toks.clear();
        split(x, d, toks);
        return toks.back();
    }

    // Eg: "C_12_D" to "C_12"
    inline Tok noLast(const Tok &x, const Tok &d)
    {
        Toks toks;
        split(x, d, toks);
        toks.pop_back();
        return join(toks, d);
    }

    inline std::string remove(const std::string &s1, const std::string &s2)
    {
        auto x = s1;
        boost::replace_all(x, s2, "");
        return x;
    }

    inline bool hasSub(const std::string &s1, const std::string &s2)
    {
        return s1.find(s2) != std::string::npos;
    }

    inline double s2d(const std::string &x)
    {
        if (x == "NA" || x == "-")
        {
            return NAN;
        }

        try
        {
            return stod(x);
        }
        catch(...)
        {
            throw std::runtime_error("Failed to parse \"" + x + "\". This is not a number.");
        }
    }

    inline long double ss2ld(const std::string &x)
    {
        if (x == "NA" || x == "-" || x == "*")
        {
            return NAN;
        }

        std::istringstream os(x);
        long double p;
        os >> p;
        return p;
    }

    // Convert floating number to scientific notation
    inline std::string ld2ss(long double p)
    {
        if (std::isnan(p) || !std::isfinite(p))
        {
            return "-";
        }

        std::ostringstream out;

        // Convert the probability into scientific notation
        out << std::scientific << p;

        return out.str();
    }

    template <typename T> std::string toString(const T &x, unsigned n = 2)
    {
        if (std::isnan(x) || !std::isfinite(x))
        {
            return "-";
        }

        std::ostringstream out;
        out << std::fixed << std::setprecision(n) << x;
        return out.str();
    }

    template <typename T> unsigned count(const std::map<T, unsigned> &x)
    {
        return std::accumulate(std::begin(x), std::end(x), 0, [](unsigned c, const std::pair<T, unsigned>& p)
        {
            return c + (p.second ? 1 : 0);
        });
    }

    template <typename X, typename F> unsigned countMap(const X &x, F f)
    {
        unsigned n = 0;

        for (const auto &i : x)
        {
            n += f(i.first, i.second);
        }

        return n;
    }

    template <typename T> double mean(const T &x)
    {
        return std::accumulate(x.begin(), x.end(), 0.0) / x.size();
    }

    template <typename T1, typename T2> T2 sum(const std::vector<T1> &x)
    {
        return std::accumulate(std::begin(x), std::end(x), T2(), [](T2 c, const T1 &p)
        {
            return c + p;
        });
    }

    template <typename T1, typename T2> unsigned nonZero(const std::map<T1, T2> &x)
    {
        unsigned n = 0;

        for (const auto &i : x)
        {
            if (i.second)
            {
                n++;
            }
        }

        return n;
    }

    typedef std::string Path;
    typedef std::string FileName;

    inline FileName path2file(const Path &path)
    {
        auto tmp = path;
        const auto last = path.find_last_of("\\/");

        if (std::string::npos != last)
        {
            tmp.erase(0, last + 1);
        }

        return tmp;
    }

    inline std::vector<FileName> path2file(const std::vector<FileName> &files)
    {
        auto tmp = files;

        for (auto i = 0; i < tmp.size(); i++)
        {
            tmp[i] = path2file(tmp[i]);
        }

        return tmp;
    }

    template <typename T1, typename T2> T2 sum(const std::map<T1, T2> &x)
    {
        return std::accumulate(std::begin(x), std::end(x), T2(), [](T2 c, const std::pair<T1, T2>& p)
        {
            return c + p.second;
        });
    }

    template <typename Key, typename Value> std::set<Key> keys(const std::map<Key, Value> &x)
    {
        std::set<Key> keys;

        for (const auto i: x)
        {
            keys.insert(i.first);
        }

        return keys;
    }
}

#endif