#!/bin/bash

# Author: John Idarraga <idarraga@cern.ch>
# Medipix Group, Universite de Montreal

# Starting up a new algorithm in MAFalda

echo
echo "[-->?] Enter the name of your new algorithm"
echo "       avoiding spaces ex: \"AlphaCalculator\""

read algoName

echo "[-->?] Choose between the available templates:"
echo "       1) Simple matrix read and processing - no Clustering."
echo "       2) Analysis after Clustering."
echo "       3) Analysis after Clustering & Pattern recognition."
echo "       4) Empty analysis.  Code skeleton only."

read algoTemplate

if [ $algoTemplate -lt 1 ]; then
    echo "[ERROR] pick up a number withing the templates range."
    exit
fi
if [ $algoTemplate -gt 4 ]; then
    echo "[ERROR] pick up a number withing the templates range."
    exit
fi

if [ -d ./$algoName ]; then
    echo "[WARNING] directory ./$algoName already exists !!!"
    echo "          hit any key to continue and OVERRIDE, or Ctrl+C to quit"
    read q1
fi

echo "[INFO] creating directory for new algorithm --> ./${algoName}"
if [ ! -d ./$algoName ]; then
    mkdir ./$algoName
fi

cd ./$algoName

echo "[INFO] creating header and implementation files"
echo "       ./${algoName}.h and ./${algoName}.cpp"
echo "        using template $algoTemplate ..."

##############################################
# template 1
if [ $algoTemplate == 1 ]; then

cat <<EOF> ./${algoName}.h
#ifndef __${algoName}_h
#define __${algoName}_h

#include "MPXAlgo/MediPixAlgo.h"

class ${algoName} : public MediPixAlgo {

public:

  ${algoName}();
  virtual ~${algoName}() { };

  // You ought to implement Init(), Execute() and Finalize()
  //  when you inherit from MediPixAlgo.  This model gives you
  //  direct access to data and services.
  void Init();
  void Execute();
  void Finalize();

private:

  typedef struct {
    Int_t totalHits;
    Int_t totalCharge;
  } score;

  score myhits;

  ClassDef(${algoName}, 1)
};

#endif
EOF


cat <<EOF> ./${algoName}.cpp
#ifndef __${algoName}_cpp
#define __${algoName}_cpp

#include "${algoName}.h"

using namespace MSG;

ClassImp(${algoName})

${algoName}::${algoName}(){

  myhits.totalCharge = 0;
  myhits.totalHits = 0;
}

void ${algoName}::Init(){

  // You will get an ntuple file containing a TTree with the name of this
  //  Algorithm.  The branches registered through getMyTree() get registered
  //  in that tree so you can fill them each time Execute() gets called.
  getMyTree()->Branch("myhits", &myhits , "totalHits/I:totalCharge");

  Log << MSG::INFO << "Init function !" << endreq;

}

void ${algoName}::Execute(){

  // REMINDER: ${algoName}::Execute() runs once per frame
  //  you may need ro reinitialize variables.
  myhits.totalCharge = 0;
  myhits.totalHits = 0;
  
  Int_t xDim = GetMatrixXdim();
  Int_t yDim = GetMatrixYdim();

  Int_t rowItr = 0;

  for(Int_t colItr = 0; colItr < xDim ; colItr++)
    {
      for(rowItr = 0; rowItr < yDim ; rowItr++)
	{
	  if(GetMatrixElement(colItr, rowItr) > 0)
	    {
	      myhits.totalCharge += GetMatrixElement(colItr, rowItr);
	      myhits.totalHits++;
	    }
	}
    }
  Log << MSG::INFO << "Total charge : " << myhits.totalCharge << endreq ;
  Log << MSG::INFO << "Total hits : " << myhits.totalHits << endreq ;

  getMyTree()->Fill();

}

void ${algoName}::Finalize(){

  Log << MSG::INFO << "Finalize function !" << endreq;

}

#endif
EOF

##############################################
# template 2
elif [ $algoTemplate == 2 ]; then

cat <<EOF> ./${algoName}.h
#ifndef __${algoName}_h
#define __${algoName}_h

#include "MPXAlgo/MediPixAlgo.h"

// This algorithm is using an object put in the StoreGate
//  by BlobsFinder. I need to know the object.
#include "BlobsFinder/BlobsFinder.h"

class ${algoName} : public MediPixAlgo {

public:

  ${algoName}();
  virtual ~${algoName}() { };

  // You ought to implement Init(), Execute() and Finalize()
  //  when you inherit from MediPixAlgo.  This model gives you
  //  direct access to data and services.
  void Init();
  void Execute();
  void Finalize();

private:

  AllBlobsContainer * m_aB;
  Int_t m_minNPixels;

  // for output
  vector<Float_t> m_distanceToCenter;

  ClassDef(${algoName}, 1)
};

#endif
EOF

cat <<EOF> ./${algoName}.cpp
/**
 * Author:  John Idarraga <idarraga@cern.ch> , 2011
 *  An example of how to use the Clustering results
 *  for further processing.
 */

#ifndef __${algoName}_cpp
#define __${algoName}_cpp

#include "${algoName}.h"
#include "MAFTools.h"

using namespace MSG;

ClassImp(${algoName})

${algoName}::${algoName}(){

}

void ${algoName}::Init(){

	Log << MSG::INFO << "Init function !" << endreq;

	// This value will be overridden by the configuration since it'll be set up
	//  a few lines below as a configuration value
	m_minNPixels = 5;

	// You will get an ntuple file containing a TTree with the name of this
	//  Algorithm.  The branches registered through getMyTree() get registered
	//  in that tree so you can fill them each time Execute() gets called.
	getMyTree()->Branch("distanceToCenter", &m_distanceToCenter);

	// A configuration value that can be tuned from the Viewer
	RegisterConfigurationValue(&m_minNPixels, "minNPixels");

}

void ${algoName}::Execute(){

	// Ask the store gate if the previous algorithm (BlobsFinder --> reponsible for clustering)
	//  sent any objects to the StoreGate.
	Int_t lastObject = GetNumberOfObjectsWithAuthor("BlobsFinder");
	if(lastObject == 0)
		return;

	// If so, get the pointer to the last object.  BlobsFinder, as it comes out of the box, sends
	//  a single object containing all clusters.
	m_aB = (AllBlobsContainer *) GetObjectFromAuthor("BlobsFinder", lastObject-1);

	// AllBlobsContainer is a box full of Blobs(Clusters). Now we can iterate over all clusters inside.
	vector<blob> blobsVector = m_aB->GetBlobsVector();
	Log << MSG::INFO << "Number of blobs from clustering = " << (Int_t) blobsVector.size() << endreq;
	vector<blob>::iterator blobsItr = blobsVector.begin(); //allBlobs.begin();

	Float_t cut = 0., slope = 0.;
	Float_t cx = 0., cy = 0.;
	Float_t pixx = 0., pixy = 0.;

	for( ; blobsItr != blobsVector.end() ; blobsItr++)
	{

		// Limit all this to clusters with a minimum size.
		// Note that m_minNPixels can be configured through the Viewer
		//  so you can reprocess and check results online.
		if((*blobsItr).bP.nPixels < m_minNPixels)
			continue;

		// BlobsFinder has pre-calculated a few characteristics on each cluster.
		// If you want to use those values you can get them here.  For instance there is a LinearRegresion
		//  off all pixels belonging to the Cluster.  Here's the slope and ycut values.
		cut = (*blobsItr).bP.fitCut;
		slope = (*blobsItr).bP.fitSlope;

		// If you want to look at this cluster in detail, i.e. pixel per pixel, you can get the contents
		//  of the cluster in the form of a list of pairs [(X,Y), counts]
		list< pair < pair<Int_t, Int_t>, Int_t > >::iterator listItr;

		for(listItr = (*blobsItr).blobContent.begin() ; listItr != (*blobsItr).blobContent.end() ; listItr++)
		{

                        // each x and y coordinate of the pixels belonging to this blob
			pixx = (Float_t)(*listItr).first.first;
			pixy = (Float_t)(*listItr).first.second;

			// As an example let's calculate the distance from each pixel to the 
                        // center of the cluster. Note the function from MAFTools !
                        cx = (*blobsItr).GetBlobProperties().geoCenter_x;
                        cy = (*blobsItr).GetBlobProperties().geoCenter_y;
			m_distanceToCenter.push_back(  MAFTools::CalcDistance(GetMatrixXdim()/2., GetMatrixXdim()/2., cx, cy)  );

			// You can naturally get the TOT and MC information if available
			//  Also lvl1 information is available for those chips who have it.
			//  See MediPixAlgo::GetLVL1(...)
			Log << MSG::DEBUG << "TOT (" << pixx << ", " << pixy << ") = "
					<< GetMatrixElement(pixx, pixy) << endreq ;
			if ( IsMCData() ) {
				Log << MSG::DEBUG << "MC energy = " << GetMatrixElementMCEdep(pixx, pixy) << endreq;
			}

		}

	}

	// Fill the output tree of this algorithm
	getMyTree()->Fill();

	// WARNING ! don't forget to clean up your variables for the next TTree::Fill call
	m_distanceToCenter.clear();

}

void ${algoName}::Finalize() {

	Log << MSG::INFO << "Finalize function !" << endreq;

}

#endif
EOF

##############################################
# template 3
elif [ $algoTemplate == 3 ]; then
    echo "not available yet.  Contact <idarraga@cern.ch> if you need this."
    exit

##############################################
# template 4
elif [ $algoTemplate == 4 ]; then
    echo "not available yet.  Contact <idarraga@cern.ch> if you need this."
    exit
fi

cd ..
echo "[INFO] appending \"${algoName}\" to buildList.Algo and buildList.LinkDef"
echo "$algoName" >> buildList.Algo
echo "$algoName" >> buildList.LinkDef

echo ""
echo "[DONE] README !!!! The new algorithm \"${algoName}\" is ready. "
echo "       You need to do the following: "
echo "       1) To compile, type --> make"
echo "       2) To run, include the following 2 lines in the file runExample.C"
echo "          The lines should go right before the line \"MPXViewer * v1 = new MPXViewer;\""
echo "             ${algoName} * ac = new ${algoName};"
echo "             mpxAnalysis.ConnectAlgo(\"${algoName}\", ac);"
echo "       3) To run, type --> root -l runExample.C"
echo "       4) If you want to run without the Viewer, comment out the line"
echo "          \"mpxAnalysis.ConnectAlgo("MPXViewer", v1);\" and run again"
echo "          You will get the results of the running algorithms in an output"
echo "          file called MAFOutput_*.root"
