#include "AnapawMode.hh"
#include <TROOT.h>
#include <iostream>

ClassImp(AnapawMode)
using namespace std;
//_____________________________________________________________________________
// maximun number of characters in line
#define ANA_MAX_CHAR_LINE 200
// maximun number of words in one command line
#define ANA_MAX_SPLIT 50
//_____________________________________________________________________________
AnapawMode::AnapawMode(){
  cout<<"[AnapawMode::AnapawMode] AnapawMode START."<<endl;
  SetDefaultComList();
}
AnapawMode::~AnapawMode(){
  cout<<"[AnapawMode::~AnapawMode] AnapawMode STOP."<<endl;
}
//_____________________________________________________________________________
bool AnapawMode::ProcessLine(TString sline){

  cout<<"[AnapawMode::ProcessLine] sline="<<sline<<endl;

  if (sline.IsNull())
    return kFALSE;

  TString slines[ANA_MAX_SPLIT];
  int n = Split(sline,slines,";");
  if (n==0) 
    return kFALSE;

  bool fIsProcessed=kFALSE;

//  cout<<"AnapawMode : n = "<<n<<endl;
  for (int i=0;i<n;i++){
//    cout<<"i="<<i<<"   "<<slines[i]<<endl;
    if (slines[i].IsNull()){  //  check empty sline
//      cout<<"AnapawMode : empty input"<<endl;
      continue;
    }
    fIsProcessed = Execute_Commandline(slines[i]) || fIsProcessed;
  }
  return fIsProcessed;
}
//_____________________________________________________________________________
bool AnapawMode::Execute_Commandline(const TString sline){
  TString word[ANA_MAX_SPLIT];

  // split a line by spaces to words
  int nword = Split(sline, word, " ");

//  for (int i=0;i<nword;i++)
//    cout<<"AnapawMode : i= "<<i<<"  :"<<word[i]<<endl;
//  cout<<"AnapawMode : nword = "<<nword<<endl;

  if (Complement_Command(word[0])){
    TString sline_converted = WordToCintCom(nword,word);
    cout<<"[AnapawMode::Execute_Commandline]sline="<<sline_converted<<endl;
    gROOT->ProcessLine(sline_converted);
//    Execute_Macro(nword,word);
  }else{
    gROOT->ProcessLine(sline);
  }
  return kTRUE;
}
//_____________________________________________________________________________
bool AnapawMode::Complement_Command(TString& inp_word){
  // complement command string from a part of command string

  TString word;
  vector<string> com_match;

  //pickup matched commands
  vector<string>::iterator it=comlist.begin();
  while (it!=comlist.end()){
    word = it->substr(0,inp_word.Length());
    if ( word == inp_word ){
      com_match.push_back(*it);
    }
    it++;
  }

  //-------------------------
  if (com_match.size()<1){
    //    cout<<"AnapawMode: No such a command"<<endl;
    return kFALSE;

  //-------------------------
  }else if(com_match.size()==1){
    vector<string>::iterator it_match=com_match.begin();
    inp_word = *it_match;
    return kTRUE;

  //-------------------------
  }else {
    cout<<"[AnapawMode::Complement_Command] Ambiguous command "<<inp_word
	<<". Possible "<<com_match.size()<<" commands are:"<<endl;
    vector<string>::iterator it_match=com_match.begin();
    while(it_match!=com_match.end()){
      cout<<*it_match<<endl;
      it_match++;
    }
    return kFALSE;
    //-------------------------
  }
}
//_____________________________________________________________________________
int AnapawMode::Split(const TString sin, TString sout[], const TString ch){

  char cline_cpy[ANA_MAX_CHAR_LINE];
  char *ctemp;

  strcpy(cline_cpy,sin.Data());
  ctemp = strtok(cline_cpy,ch.Data());
  int n=0;
  while(ctemp !=NULL){
    sout[n]=(TString)ctemp;  
    sout[n]=sout[n].Strip(TString::kBoth);
    n++;
    if (n==ANA_MAX_SPLIT){
      cout<<"[AnapawMode::Split] Max# of Command Line is "
	  <<ANA_MAX_SPLIT<<", some commands are ignored."<<endl;
      break;
    }
    ctemp = strtok(NULL,ch.Data());
  }
  return n;
}
//_____________________________________________________________________________
TString AnapawMode::WordToCintCom(const int n, const TString sin[]){

  TString sout;

  // check Cint type command 
  if (sin[0].Index(".")==0) return sin[0];

  if (n==1){
    if (sin[0].Index("(")<0 && sin[0].Index("(")<0 )
      return sin[0]+"()";
    else
      return sin[0];
  }

  // convert to Cint type command
  sout = sin[0]+"(";
  for(int i=1;i<n-1;i++){
    sout += sin[i] + ",";
  }
  sout += sin[n-1] + ")";
  return sout;
}
//_____________________________________________________________________________
bool AnapawMode::Execute_Macro(const int nword, const TString word[]){
//----- call each command from Macro/***.C -----

  string comline;
    // avy ------------------------------------------------------
  if  ( word[0] == "avy" ){
    if (nword==2) {
      comline = ".x avy.C("+word[1]+")";
      gROOT->ProcessLine(comline.c_str());
    }else if (nword==3){
      comline = ".x avy.C("+word[1]+",\""+word[2]+"\")";
      gROOT->ProcessLine(comline.c_str());
    }else {
      cout<<"AnapawMode : avy HID"<<endl;
      return kTRUE;
    }

    // bnx ------------------------------------------------------
  } else if  ( word[0] == "bnx" ){
    if (nword<4){
      cout<<"AnapawMode : bnx HID y1 y2"<<endl;
      return kTRUE;
    }
    comline = ".x bnx.C("+word[1]+","+word[2]+","+word[3]+")";
    gROOT->ProcessLine(comline.c_str());

    // bny ------------------------------------------------------
  } else if  ( word[0] == "bny" ){
    if (nword<4){
      cout<<"AnapawMode : bnx HID x1 x2"<<endl;
      return kTRUE;
    }
    comline = ".x bny.C("+word[1]+","+word[2]+","+word[3]+")";
    gROOT->ProcessLine(comline.c_str());

    // fetch ------------------------------------------------------
  } else if  ( word[0] == "fetch" ){
    if (nword<2) {
      cout<<"AnapawMode : fetech FILENAME"<<endl;
      return kTRUE;
    }
    comline = "TFile f(\""+word[1]+"\")";
    gROOT->ProcessLine(comline.c_str());

    // figa  ------------------------------------------------------
  } else if  ( word[0] == "figa" ) {
    comline = word[1]+"->Draw()";
    gROOT->ProcessLine(comline.c_str());

    comline = ".x figa.C("+word[1]+")";
    gROOT->ProcessLine(comline.c_str());

    // hstatus ------------------------------------------------------
  } else if ( word[0] == "hstatus"){
    if (nword<2){
      cout<<"AnapawMode : hstatus HID"<<endl;
      return kTRUE;
    }
    comline = ".x hstatus.C("+word[1]+")";
    gROOT->ProcessLine(comline.c_str());

  // ht ------------------------------------------------------
 } else if         ( word[0] == "ht" ) {
    if (word[1].IsNull()){
      return kTRUE;
    }
    if (nword==2){
      comline = word[1]+"->Draw()";
    }else  if (nword>2) {
      comline = word[1]+"->Draw(\""+word[2]+"\")";
    }
    gROOT->ProcessLine(comline.c_str());

    // i ------------------------------------------------------
  } else if  ( word[0] == "i" ){
    gROOT->ProcessLine(".ls");

    // lnx ------------------------------------------------------
  } else if  ( word[0] == "lnx" ){
    gROOT->ProcessLine("gPad->SetLogx(0)");
    // lgx ------------------------------------------------------
  } else if  ( word[0] == "lgx" ){
    gROOT->ProcessLine("gPad->SetLogx(1)");
    // lny ------------------------------------------------------
  } else if  ( word[0] == "lny" ){
    gROOT->ProcessLine("gPad->SetLogy(0)");
    // lgy ------------------------------------------------------
  } else if  ( word[0] == "lgy" ){
    gROOT->ProcessLine("gPad->SetLogy(1)");
    // lnz ------------------------------------------------------
  } else if  ( word[0] == "lnz" ){
    gROOT->ProcessLine("gPad->SetLogz(0)");
    // lgz ------------------------------------------------------
  } else if  ( word[0] == "lgz" ){
    gROOT->ProcessLine("gPad->SetLogz(1)");

    // mami  ------------------------------------------------------
  } else if  ( word[0] == "mami" ) {
    if (nword<3){
      cout<<"AnapawMode : mami HID y1 y2"<<endl;
      return kTRUE;
    }
    comline = ".x mami.C("+word[1]+","+word[2]+","+word[3]+")";
    gROOT->ProcessLine(comline.c_str());

    // mkfig  ------------------------------------------------------
  } else if  ( word[0] == "mkfig" ) {
    if (nword<2) 
      return kTRUE;
    comline = "gPad->SaveAs(\""+word[1]+"\")";
    gROOT->ProcessLine(comline.c_str());

    // prx ------------------------------------------------------
  } else if  ( word[0] == "prx" ){
    if (word[1].IsNull()){
      cout<<"AnapawMode : prx HID"<<endl;
      return kTRUE;
    }
    comline = word[1]+"->ProjectionX()->Draw()";
    gROOT->ProcessLine(comline.c_str());

    // pry ------------------------------------------------------
  } else if  ( word[0] == "pry" ){
    if (word[1].IsNull()){
      cout<<"AnapawMode : pry HID"<<endl;
      return kTRUE;
    }
    comline = word[1]+"->ProjectionY()->Draw()";
    gROOT->ProcessLine(comline.c_str());

    // pry ------------------------------------------------------
  } else if  ( word[0] == "shell" ){
    comline = ".!";
    for(int i=1;i<nword;i++){
      comline += " " + word[i];
    }
    gROOT->ProcessLine(comline.c_str());

    // xblow ------------------------------------------------------
  } else if  ( word[0] == "xblow" ){
    if (nword<4){
      cout<<"AnapawMode : xblow HID x1 x2"<<endl;
      return kTRUE;
    }
    comline = ".x xblow.C("+word[1]+","+word[2]+","+word[3]+")";
    gROOT->ProcessLine(comline.c_str());

    // xfitg  ------------------------------------------------------
  } else if  ( word[0] == "xfitg" ) {
    if (nword==2){
      comline = word[1]+"->Draw()";
      gROOT->ProcessLine(comline.c_str());
      comline = ".x xfitg.C("+word[1]+")";
    }else if (nword==4){
      comline = word[1]+"->Draw()";
      gROOT->ProcessLine(comline.c_str());
      comline = ".x xfitg.C("+word[1]+","+word[2]+","+word[3]+")";
    }else{
      cout<<"AnapawMode : xfitg HID [x1 x2]"<<endl;
      return kTRUE;
    }
    gROOT->ProcessLine(comline.c_str());

    // xfitl  ------------------------------------------------------
  } else if  ( word[0] == "xfitl" ) {
    if (nword==2){
      comline = word[1]+"->Draw()";
      gROOT->ProcessLine(comline.c_str());
      comline = ".x xfitl.C("+word[1]+")";
    }else if (nword==4){
      comline = word[1]+"->Draw()";
      gROOT->ProcessLine(comline.c_str());
      comline = ".x xfitl.C("+word[1]+","+word[2]+","+word[3]+")";
    }else{
      cout<<"AnapawMode : xfitl HID [x1 x2]"<<endl;
      return kTRUE;
    }
    gROOT->ProcessLine(comline.c_str());

    // xstatus ------------------------------------------------------
  } else if ( word[0] == "xstatus"){
    if(nword==2 ){
      comline = word[1]+"->Draw()";
      gROOT->ProcessLine(comline.c_str());
      comline=".x xstatus.C("+word[1]+")";
    }else if(nword==4 ){
      comline = word[1]+"->Draw()";
      gROOT->ProcessLine(comline.c_str());
      comline=".x xstatus.C("+word[1]+","+word[2]+","+word[3]+")";
    }else{
      cout<<"AnapawMode : xstatus HID [x1 x2]"<<endl;
      return kTRUE;
    }
    gROOT->ProcessLine(comline.c_str());

    // xyblow ------------------------------------------------------
  } else if  ( word[0] == "xyblow" ){
    if (nword<6){
      cout<<"AnapawMode : xblow HID x1 x2 y1 y2"<<endl;
      return kTRUE;
    }
    comline = ".x xyblow.C("+word[1]+","+word[2]+","+word[3]
      +","+word[4]+","+word[5]+ ")";
    gROOT->ProcessLine(comline.c_str());

    // else ------------------------------------------------------
  } else {
    return kFALSE;
  }
  return kTRUE;
}
//_____________________________________________________________________________
void AnapawMode::AddComList(string s){

  vector<string>::iterator it=comlist.begin();
  while(it!=comlist.end()){
    if (*it==s) {
      cout<<endl<<"[AnapawMode::AddComList]  command \""
	  <<s<<"\" has already been registered!, "
	  <<"check AnapawMode::SetDefaultComList."<<endl<<endl;
      return;
    }
  it++;
  }
  comlist.push_back(s);
  return;
}
//_____________________________________________________________________________
void AnapawMode::SetDefaultComList(){
  AddComList("ht");
  AddComList("fetch");
  AddComList("i");
  AddComList("hn");
  AddComList("hb");
  AddComList("lnx");
  AddComList("lgx");
  AddComList("lny");
  AddComList("lgy");
  AddComList("lnz");
  AddComList("lgz");
  AddComList("cpro");
  AddComList("hcut");
  AddComList("avy");
  AddComList("cdraw");
  AddComList("listgate");
  AddComList("prx");
  AddComList("pry");
  AddComList("bnx");
  AddComList("bny");
  AddComList("slx");
  AddComList("xly");
  AddComList("xstatus");
  AddComList("hstatus");
  AddComList("xfitl");
  AddComList("xfitg");
  AddComList("mami");
  AddComList("blow");
  AddComList("xblow");
  AddComList("xyblow");
  AddComList("hstore");
  AddComList("clear");
  AddComList("xval");
  AddComList("yval");
  AddComList("xyval");
  AddComList("chbin");
  AddComList("status");
  AddComList("mkfig");
//  AddComList("shell");
  AddComList("ls");
  AddComList("zone");
  AddComList("zoom");

  //temp
  AddComList("mkfig");

  sort(comlist.begin(),comlist.end());
}
//_____________________________________________________________________________
void AnapawMode::ShowComList(){
  vector<string>::iterator it=comlist.begin();
  while(it!=comlist.end()){
    cout<<*it<<endl;
    it++;
  }
}
//_____________________________________________________________________________


