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

ClassImp(AnapawMode)
using namespace std;
//_____________________________________________________________________________
// maximun number of characters in line
#define ANA_MAX_CHAR_LINE 1000
// 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);
  }else{
    gROOT->ProcessLine(sline);
  }
  return kTRUE;
}
//_____________________________________________________________________________
bool AnapawMode::Complement_Command(TString& inp_word){
  // complement command string from a part of command string

  TString word;
  list<string> com_match;

  //pickup matched commands
  list<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){
    list<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;
    list<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[]){
  /* Convert Anapaw-like command line to Cint-like one. */

  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;
}
//_____________________________________________________________________________
void AnapawMode::AddComList(string s){

  list<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;
      return;
    }
  it++;
  }
  comlist.push_back(s);
  return;
}
//_____________________________________________________________________________
void AnapawMode::ShowComList(){
  list<string>::iterator it=comlist.begin();
  while(it!=comlist.end()){
    cout<<*it<<endl;
    it++;
  }
}
//_____________________________________________________________________________
#include "defcomlist.cc"
//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");
//
//  comlist.sort();
//}
//_____________________________________________________________________________


