#include "Operand.h"
#include "Exception.h"
#include <format>
#include <iostream>

namespace jet {

   Operand::Operand(coreutils::ZString &in) {

      doubleValue = 0;
      
      in.skipWhitespace();

      if(in.ifNext("(")) {
	 Operand op(in);
	 string = op.string;
	 doubleValue = op.doubleValue;
	 if(!in.ifNext(")")) 
	   throw coreutils::Exception("expected ) in expression.");	      
      } 
      
      if(in.ifNext("SUBSTRING")) {
	 if(!in.ifNext("("))
	   throw coreutils::Exception("Expecting ( for SUBSTRING parameters.");
	 Operand parm1(in);
	 if(!in.ifNext(","))
	   throw coreutils::Exception("Expecting , in SUBSTRING expression.");
	 Operand parm2(in);
	 if(in.ifNext(")")) {
	    string = parm1.string.substring(parm2.string.asInteger());
	 }
	 else if(!in.ifNext(","))
	   throw coreutils::Exception("Expecting , in SUBSTRING expression.");
	 Operand parm3(in);
	 if(in.ifNext(")")) {
	    string = parm1.string.substring(parm2.string.asInteger(), parm3.string.asInteger());
	 }
	 else
	   throw coreutils::Exception("Expecting ) at end of substring expression.");
      } else if(in.ifNext("LEFT")) {
	 if(!in.ifNext("("))
	   throw coreutils::Exception("Expecting ( for LEFT parameters.");
	 Operand parm1(in);
	 if(!in.ifNext(","))
	   throw coreutils::Exception("Expecting , in LEFT expression.");
	 Operand parm2(in);
	 if(in.ifNext(")")) {
	    string = parm1.string.substring(0, parm2.string.asInteger());
	 }
	 else
	   throw coreutils::Exception("Expecting ) at end of LEFT expression.");	 
      } else if(in.ifNext("RIGHT")) {
	 
      } else if(in.ifNext("TRIM")) {
	 
      } else if(in.ifNext("TOUPPER")) {
	 
      } else if(in.ifNext("TOLOWER")) {
	 
      } else if(in.ifNext("REVERSE")) {
	 
      } else if(in.ifNext("CONCAT")) {
	 
      } else if(in.ifNext("INTEGER")) {
	 
      } else if(in.ifNext("ROUND")) {
	 
      } else if(in.ifNext("RANDOM")) {
	 
      } else if(in.ifNext("true")) {
	 boolean = true;
	 string = "true";
      } else if(in.ifNext("false")) {
	 boolean = false;
	 string = "false";
      } else if(in.startsWithNumber()) {
	 doubleValue = in.asDouble();
	 string = std::format("{}", doubleValue);
	 isNumber = true;
      } else if(in.ifNext("'")) {
	 string = in.getTokenExclude("'");
	 in.ifNext("'");
	 isNumber = false;
      }

      in.skipWhitespace();     

      if(in.ifNext("=")) {
	 Operand op(in);
	 if(isNumber && op.isNumber) {
	    if(doubleValue == op.doubleValue) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	      
	 } else if(!isNumber && !op.isNumber) {
	    if(string == op.string) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	    
	 }	   
      }      
      if(in.ifNext("<")) {
	 Operand op(in);
	 if(isNumber && op.isNumber) {
	    if(doubleValue < op.doubleValue) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	      
	 } else if(!isNumber && !op.isNumber) {
	    if(string < op.string) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	    
	 }	   
      }      
      if(in.ifNext(">")) {
	 Operand op(in);
	 if(isNumber && op.isNumber) {
	    if(doubleValue > op.doubleValue) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	      
	 } else if(!isNumber && !op.isNumber) {
	    if(string > op.string) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	    
	 }	   
      }
      if(in.ifNext("!=") || in.ifNext("<>")) {
	 Operand op(in);
	 if(isNumber && op.isNumber) {
	    if(doubleValue != op.doubleValue) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	      
	 } else if(!isNumber && !op.isNumber) {
	    if(string != op.string) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	    
	 }	   
      }      
      if(in.ifNext("<=")) {
	 Operand op(in);
	 if(isNumber && op.isNumber) {
	    if(doubleValue <= op.doubleValue) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	      
	 } else if(!isNumber && !op.isNumber) {
	    if(string <= op.string) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	    
	 }	   
      }            
      if(in.ifNext(">=")) {
	 Operand op(in);
	 if(isNumber && op.isNumber) {
	    if(doubleValue >= op.doubleValue) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	      
	 } else if(!isNumber && !op.isNumber) {
	    if(string >= op.string) {
	       boolean = true;
	       isNumber = false;
	       string = "true";
	    } else {
	       boolean = false;
	       isNumber = false;
	       string = "false";
	    }	    
	 }	   
      }      
      if(in.ifNext("+")) {
	 if(isNumber) {	      
	    Operand op(in);
	    if(op.isNumber) {
	       doubleValue += op.doubleValue;
	       string = std::format("{}", doubleValue);	       
	    } else
	      throw coreutils::Exception("operand is not a number.");
	 } else
	   throw coreutils::Exception("operand is not a number.");	 
      } else if(in.ifNext("-")) {
	 if(isNumber) {	      
	    Operand op(in);
	    if(op.isNumber) {
	       doubleValue -= op.doubleValue;
	       string = std::format("{}", doubleValue);	       
	    } else
	      throw coreutils::Exception("operand is not a number.");
	 } else
	   throw coreutils::Exception("operand is not a number.");	 
      } else if(in.ifNext("*")) {
	 if(isNumber) {	      
	    Operand op(in);
	    if(op.isNumber) {
	       doubleValue *= op.doubleValue;
	       string = std::format("{}", doubleValue);	       
	    } else
	      throw coreutils::Exception("operand is not a number.");
	 } else
	   throw coreutils::Exception("operand is not a number.");	 
      } else if(in.ifNext("/")) {
	 if(isNumber) {	      
	    Operand op(in);
	    if(op.isNumber) {
	       doubleValue /= op.doubleValue;
	       string = std::format("{}", doubleValue);	       
	    } else
	      throw coreutils::Exception("operand is not a number.");
	 } else
	   throw coreutils::Exception("operand is not a number.");	 
      } else {
//	 std::cout << ">" << string << std::endl;
	 return;
      }
     
   }
   
}
