#include "Behaviors/StateMachine.h"
#include "DualCoding/DualCoding.h"
#include "Vision/SIFT/API/SiftTekkotsu.h"
#include "local/tekkotsu/Simulator.h"
#include <vector>
#include <string>
#include <iostream>
#include <sstream>

using namespace DualCoding;
using namespace std;

#nodeclass StructuredSiftAppendBehavior : VisualRoutinesStateNode : siftInfo()

struct SiftVariables {
  SiftVariables() : object(0), objectname(""), typeobject(""), mySiftTekkotsu(), buff(), results() {}
  int object;
  string objectname, typeobject;
  SiftTekkotsu mySiftTekkotsu;
  ImageBuffer buff;
  vector<SiftMatch*> results;
} siftInfo;

#nodeclass DBAsk : StateNode
virtual void doStart() {
  cout << "Make a new database or open the old one(n/o)?\n";
  postStateCompletion();
}
#endnodeclass

#nodeclass DBAns : StateNode
virtual void doStart() {
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  
  if (tolower(txtev.getText()[0]) == 'n')
    postStateFailure();
  else if (tolower(txtev.getText()[0] == 'o'))
    postStateCompletion();
}
#endnodeclass

#nodeclass DBLoad : StateNode
virtual void doStart() {
  SiftVariables &siftInfo = parentAs<StructuredSiftAppendBehavior>()->siftInfo;
  siftInfo.mySiftTekkotsu.loadFile("/afs/cs.cmu.edu/user/joehan/sift-toolData/tekkotsu.date");
  postStateCompletion();
}
#endnodeclass


#nodeclass AddPicture : StateNode
virtual void doStart() {
  cout << "Do you wish to add this picture to the database(y/n)? \n"; 
}
#endnodeclass

#nodeclass AnsAddPicture : StateNode // Continue Here
virtual void doStart() {
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  if (tolower(txtev.getText()[0]) == 'n') {
    cout << "Do you wish to change the picture(y/n)? \n";
    postStateFailure();
  }
  else if (tolower(txtev.getText()[0]) == 'y') {
    cout << "New object or adding a model to an object (n/a)? \n";  
    postStateCompletion();
  }
}
#endnodeclass

#nodeclass ChangePicture : StateNode // Continue Here
virtual void doStart() {
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  if (tolower(txtev.getText()[0]) == 'y') {
    ProjectInterface::sendCommand("advance");
  }
  // postStateCompletion();
}
#endnodeclass

#nodeclass AppendInfo : StateNode // All commands to work with the append
virtual void doStart() {
  //SiftVariables &siftInfo = parentAs<SiftAppendBehavior>()->siftInfo;
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);

  if (tolower(txtev.getText()[0]) == 'n') {
    cout << "Object name:\n";
    postStateCompletion();// Division
  }
  else if (tolower(txtev.getText()[0]) == 'a') {
    cout << "Current model or other model(c/o)?\n";
    postStateFailure();// Division
  }
}
#endnodeclass
    
#nodeclass AnsAppendInfo1 : StateNode // First query in AppendInfo, making a new object
virtual void doStart() {
  SiftVariables &siftInfo = parentAs<StructuredSiftAppendBehavior>()->siftInfo;
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  siftInfo.objectname = txtev.getText();
  cout << siftInfo.objectname << endl; // Continuation
  NEW_SKETCH(camGrey, uchar, sketchFromRawY());
  siftInfo.buff = siftInfo.mySiftTekkotsu.sketchToBuffer(camGrey);
  siftInfo.object = siftInfo.mySiftTekkotsu.train_addNewObject(siftInfo.buff);
  siftInfo.mySiftTekkotsu.setObjectName(siftInfo.object, siftInfo.objectname);
  cout << "Do you wish to continue (y/n)\n?";
  postStateCompletion();
}
#endnodeclass

#nodeclass AnsAppendInfo2 : StateNode // Second query in AppendInfo, adding a model to an already made object 
virtual void doStart() {
  SiftVariables &siftInfo = parentAs<StructuredSiftAppendBehavior>()->siftInfo;
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  if (tolower(txtev.getText()[0]) == 'c') {
    siftInfo.mySiftTekkotsu.train_addToObject(siftInfo.object, siftInfo.buff);
    cout << "Do you wish to continue (y/n)?\n";
    postStateCompletion();
  }
  else if (tolower(txtev.getText()[0]) == 'o') {
    cout << "What is the object name?\n";
    postStateFailure();// Division
  }
}
#endnodeclass

#nodeclass String2AnsAppendInfo2 : StateNode // Sending String data to look for an object    
virtual void doStart() {    // Contiuation
  SiftVariables &siftInfo = parentAs<StructuredSiftAppendBehavior>()->siftInfo;
  // const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  siftInfo.object = siftInfo.mySiftTekkotsu.getObjectID(siftInfo.objectname);
  if (siftInfo.object < 0) {
    cout << "Said object does not exist. Try again.\n";
    postStateFailure();
  }
  else {
    siftInfo.mySiftTekkotsu.train_addToObject(siftInfo.object, siftInfo.buff); 
    cout << "Do you wish to continue (y/n)?\n";
    postStateCompletion();
  }
}
#endnodeclass

#nodeclass GoBackUp : StateNode
virtual void doStart() {
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  
  // Continuation
  if (tolower(txtev.getText()[0]) == 'y') {
    postStateFailure();
  }
  else {
    cout << "Do you wish to save changes(y/n)?\n";
    postStateCompletion();
  }
}
#endnodeclass

#nodeclass SaveDataBase : StateNode
virtual void doStart() {
  SiftVariables &siftInfo = parentAs<StructuredSiftAppendBehavior>()->siftInfo;
  const TextMsgEvent &txtev = *dynamic_cast<const TextMsgEvent*>(event);
  
  // Continuation
  if (tolower(txtev.getText()[0]) == 'y') {
    system("mkdir -p ~/sift-toolData/"); // ch
    siftInfo.mySiftTekkotsu.saveToFile("/afs/cs.cmu.edu/user/joehan/sift-toolData/tekkotsu.date", true);
    cout << "Changes saved!\n";
    cout << "Have a good time!\n";
  }
  else {
    cout << "Changes were not saved!\n"
	 << "Have a good time!\n";
  } 
}
#endnodeclass

virtual void setup() {
#statemachine
  // Documentation below
 dba: DBAsk =TM("n")=> ap
    dba =TM("o")=> dbl
    dbl: DBLoad =C=> ap
    ap: AddPicture =TM=> aap
    aap: AnsAddPicture =F=> StateNode =TM("y")=> cp // Problem here
    aap =F=> StateNode =TM("n")=> gbu // and here 
    aap =C=> StateNode =TM=> ai
    cp: ChangePicture =T(100)=> ap
    ai: AppendInfo =C=> StateNode =TM=> aai1
    ai =F=> StateNode =TM=> aai2
    aai1: AnsAppendInfo1 =C=> StateNode =TM=> gbu
    aai2: AnsAppendInfo2 =F=> StateNode =TM=> s2aai2
    aai2 =C=> StateNode =TM=> gbu
    s2aai2: String2AnsAppendInfo2 =F=> ap
    s2aai2 =C=> StateNode =TM=> gbu
    gbu: GoBackUp =F=> ap
    gbu =C=> StateNode =TM=> sDB
    sDB: SaveDataBase
#endstatemachine
    }

/** Documentation:
  * DBLoad loads the database. (=C=>AddPicture)
  * AddPicture asks user if he/she wants to add the current picture. (=C=>AnsAddPicture)
  * AnsAddPicture changes or continues with the current picture. (=F=>ChangePicture; =C=>AppendInfo)
  * ChangePicture changes the picture.(=C=>AddPicture)
  * AppendInfo asks if the user wants to add a new object or add a model to a previous object. (=C=>AnsAppendInfo1; =F=>AnsAppendInfo2)
  * AnsAppendInfo1 adds a new object to the database. (=C=>GoBackUp)
  * AnsAppendInfo2 adds a new model to an object already created.(=C=>String2AnsAppendInfo2)
  * String2AnsAppendInfo2 asks for an objectname.(=C=>GoBackUp)
  * GoBackUp goes back up unless the user asks to leave. (=F=>AddPicture; =C=>SaveDataBase)
  * SaveDataBase saves the database and exits the program. (End)
  **/
// =TM("y")=> // Search for "y"
#endnodeclass

REGISTER_BEHAVIOR(StructuredSiftAppendBehavior);
