/*******************************************************************
 * Function Name: GetSavePath
 * Return Type 	: const string
 * Created On	: Nov 18, 2013
 * Created By 	: hrushi
 * Comments		: Get the save path for the given algo type
 * Arguments	: const Args& args, const string AlgoType
 *******************************************************************/
const string GroundTruth::GetSavePath( const Args& args ) const
{
	string ScoreSavePath = args.GetSearchFolderPath();

	const string AlgoTypeOpt = boost::to_lower_copy( args.GetDetectMode() );

	if( AlgoTypeOpt == "pose" )
	{
		ScoreSavePath += POSE_PROB_SCORE_FILE;
	}
	else if( AlgoTypeOpt == "location"  )
	{
		ScoreSavePath += LOC_PROB_SCORE_FILE;
	}
	else if( AlgoTypeOpt == "shape")
	{
		ScoreSavePath += SHAPE_PROB_SCORE_FILE;
	}
	else if( AlgoTypeOpt == "appearance")
	{
		ScoreSavePath += APPR_PROB_SCORE_FILE;
	}

	return ScoreSavePath;
}
/*******************************************************************
 * Function Name: Open
 * Return Type 	: int
 * Created On	: Feb 26, 2013
 * Created By 	: hrushi
 * Comments		: Opens the Feature File
 * Arguments	: const Args& args, const unsigned int Mode
 *******************************************************************/
int Features::Open( const Args& args, const unsigned int Mode)
{

	FilePath = args.GetSearchFolderPath() + APPEARANCE_FEATURES;

	if( Mode == WRITE_MODE )
	{
		fPtr.open( FilePath.string().c_str(), fstream::out );
		bWBanner = true;
	}
	else
	{
		if( fs::exists( FilePath ))
		{
			cout << "Feature File Already Exist " << endl;
			bWBanner = false; // Since the file is already present, we should not populate it with the background
		}

		fPtr.open(FilePath.string().c_str() , fstream::in | fstream::out | fstream::app);

	}

	if( !fPtr.is_open() )
	{
		cerr << "Cannot Open Feature File "<< FilePath.string() << endl;
		exit(ERR_CANNOT_OPEN_FILE);
	}

	return EXIT_SUCCESS;
}
/*******************************************************************
 * Function Name: SaveChipMap
 * Return Type 	: int
 * Created On	: Nov 3, 2013
 * Created By 	: hrushi
 * Comments		: Save a map of chips
 * Arguments	: const mp_Str_vStr& mp
 *******************************************************************/
int AlgoTrain::SaveChipMap( const mp_Str_vStr& mp, const Args& args) const
{
	cv::FileStorage fsLblChips;

	string TrainFldrPath = args.GetTrainFolderPath();

	if( TrainFldrPath.length() == 0)
	{
		TrainFldrPath = args.GetSearchFolderPath();
	}

	const string LblPath = TrainFldrPath + CHIP_FILE_LIST;
	fsLblChips.open(LblPath, cv::FileStorage::WRITE);

	vector<string> vCat;
	for(mp_Str_vStr::const_iterator itr = mp.begin(); itr != mp.end(); itr++ )
	{
		vCat.push_back(itr->first);
		fsLblChips << itr->first << itr->second;
	}

	fsLblChips << "Categories" << vCat;
	fsLblChips.release();

	return EXIT_SUCCESS;
}
/*******************************************************************
 * Function Name: CalculateLocationPriorProbs
 * Return Type 	: ProbImg
 * Created On	: Jul 15, 2013
 * Created By 	: hrushi
 * Comments		: Calculates the prior probability of an
 * Arguments	: const vector<ProbImg>& vPrbImgs, const Args& args
 *******************************************************************/
int PriorProb::CalculateLocationPriorProbs( const vector<ProbImg>& vPrbImgs, const Args& args )
{
	ProbImg CombinedProbImg = vPrbImgs.at(0) + vPrbImgs.at(1);
	CombinedProbImg = CombinedProbImg + vPrbImgs.at(2);

	m_LocationPriorProb = CombinedProbImg;
	m_LocationPriorProb.Display(DISP_DELAY);

	string FolderPath = args.GetTrainFolderPath();
	if( FolderPath.length() == 0 )
	{
		FolderPath = args.GetSearchFolderPath();
	}
	const string ImgPath = FolderPath + LOC_PRIOR_PROB_IMGNAME;
	m_LocationPriorProb.SetImagePath(ImgPath);
	m_LocationPriorProb.Write( ImgPath );

	return EXIT_SUCCESS;
}
/*******************************************************************
 * Function Name: LoadChipMap
 * Return Type 	: mp_Str_vStr
 * Created On	: Nov 4, 2013
 * Created By 	: hrushi
 * Comments		: Save the chips
 * Arguments	: const Args& args
 *******************************************************************/
mp_Str_vStr AlgoTrain::LoadChipMap( const Args& args) const
{
	mp_Str_vStr Retmp;

	cv::FileStorage fsLblChips2;
	vector<string> Categories, ImPaths;

	string TrainFldrPath = args.GetTrainFolderPath();

	if( TrainFldrPath.length() == 0)
	{
		TrainFldrPath = args.GetSearchFolderPath();
	}

	const string LblPath = TrainFldrPath + CHIP_FILE_LIST;
	cout << "Reading " << LblPath << endl;

	if(!fs::exists(LblPath))
	{
		cerr << "File Path " << LblPath << " Not found" << endl;
		throw ERR_INVALID_PATH;
	}


	fsLblChips2.open(LblPath, cv::FileStorage::READ);

	fsLblChips2["Categories"] >> Categories;


	for(UINT i = 0;  i < Categories.size(); i++ )
	{
		vector<string> vImgNames;
		fsLblChips2[Categories.at(i)] >> vImgNames;
		Retmp[Categories.at(i)] = vImgNames;
	}

	fsLblChips2.release();

	return Retmp;
}
/*******************************************************************
 * Function Name: GetImageChips
 * Return Type 	: int
 * Created On	: Nov 1, 2013
 * Created By 	: hrushi
 * Comments		: Get image chips
 * Arguments	: const Args& args
 *******************************************************************/
mp_Str_vStr AlgoTrain::GetImageChips( const Args& args, const std::map<string, string>& TrkMskMap ) const
{
	static Labels Lbl(args, ALL_LABEL_FILENAME);
	Lbl.Read(args);
	tdef_LabelMap lMap = Lbl.GetLabelMap();

	string TrainFolderPath = args.GetTrainFolderPath();

	if(TrainFolderPath.length() == 0 )
	{
		TrainFolderPath = args.GetSearchFolderPath();
	}

	const string ChipPath = TrainFolderPath + CHIP_FILE_LIST;

	std::map<UINT, string> mpChips = CreateFolders(TrainFolderPath);

	UINT uiPersonChipCnt(0), uiDragCnt(0), uiWornCnt(0);
	vector<string> vPersonImgs, vDragImgs, vWornImgs;

	for (tdef_LabelMap::const_iterator itr = lMap.begin(); itr != lMap.end(); itr++)
	{
		fs::path ImagePath 	= itr->first;
		int MarkLabel		= Lbl.AlreadyPresent(itr->first);
		string CmplImgPath 	  =  Lbl.GetComplateImgFilePath(itr->first);

		//---------- Skip the loop if the image is not present ---------- //
		if(!fs::exists(CmplImgPath))
		{
			continue;
		}

		string sMaskImagePath = "";

		try
		{
			sMaskImagePath = TrkMskMap.at(CmplImgPath);
		}
		catch(const std::out_of_range& oor)
		{
			cerr << "Skip the loop as " << sMaskImagePath << " Not present" << endl;
		}

		ColorImg ProbeImg = ColorImg(CmplImgPath);
		GrayImg MskImg    = GrayImg( sMaskImagePath );

		ContourMap Segments = Detect::GetSegments(ProbeImg, MskImg , false, args);

		//---------- Get type of label. Possible optimization over here. Label files are read again and again ---------- //
		UINT LabelType = Detect::GetType(itr->first, args);

		string FldrPath = mpChips.at(LabelType);

		//Starting from iCntr = 1; Because, iCntr = 0 is Background Contour
		for( int iCntr = 1; iCntr < (int)Segments.AllContourMap.size(); iCntr++ )
		{
			Contour Ctr = Segments.AllContourMap.at(iCntr);
			ColorImg ChipImg = Ctr.GetImgChip(ProbeImg);

			cv::SIFT sift;
			vector<cv::KeyPoint> vkeypoints;
			Mat descriptors;
			Mat WorkImg = ChipImg.GetDataRef().clone();
			sift(WorkImg, Mat(), vkeypoints, descriptors);


			if(0) // Draw keypoints, not used, as it takes a lot of time.
			{
				Mat DispMat;
				cv::drawKeypoints(WorkImg, vkeypoints, DispMat);

				ColorImg DispImg;
				DispImg.SetImage(DispMat);
				DispImg.Display(DISP_DELAY);

				cout << "#Keypoints: " << vkeypoints.size() << endl;

				//---------- Skip the chip if the number of keypoints are less than the number of clusters. ---------- //
				if( vkeypoints.size() < BOW_CLUSERS )
				{
					continue;
				}

			}


			std::stringstream ss;
			if( ( LabelType == DRAG_CARRY_LABEL) && ( Ctr.GetLabel() == (UINT)MarkLabel ))
			{
				FldrPath = mpChips.at(DRAG_CARRY_LABEL);
				ss << FldrPath << "/";
				ss << DRAG << std::setfill('0') << std::setw(4) << uiDragCnt << IMG_EXT_PNG;
				uiDragCnt++;

				fs::path RelativePath = FileSystem::MakeRelative(ChipPath, ss.str());

				vDragImgs.push_back(RelativePath.string());


			}
			else if( ( LabelType == WORN_CARRY_LABEL) && ( Ctr.GetLabel() == (UINT)MarkLabel ) )
			{
				FldrPath = mpChips.at(WORN_CARRY_LABEL);
				ss << FldrPath << "/";
				ss << WORN << std::setfill('0') << std::setw(4) << uiWornCnt << IMG_EXT_PNG;
				uiWornCnt++;

				fs::path RelativePath = FileSystem::MakeRelative(ChipPath, ss.str());

				vWornImgs.push_back(RelativePath.string());

			}
			else
			{
				FldrPath = mpChips.at(PERSON_LABEL);
				ss << FldrPath << "/";
				ss << PERSON << std::setfill('0') << std::setw(4) << uiPersonChipCnt << IMG_EXT_PNG;
				uiPersonChipCnt++;

				fs::path RelativePath = FileSystem::MakeRelative(ChipPath, ss.str());

				vPersonImgs.push_back(RelativePath.string());
			}

			cout << ss.str() << endl;
			ChipImg.Write(ss.str());
		}

	}

	mp_Str_vStr mpLbl_ChipImgs;
	mpLbl_ChipImgs[PERSON] 	= vPersonImgs;
	mpLbl_ChipImgs[WORN]	= vWornImgs;
	mpLbl_ChipImgs[DRAG]	= vDragImgs;

	return mpLbl_ChipImgs;
}