#include "JString.h"
#include "Exception.h"

namespace coreutils {

   JString::JString() : MString("{}") {}

   JString::JString(const char *data) : MString(data) {}

   void JString::set(ZString path, const char *value) {
      reset();
      if(locate(path)) {
         push();
         if(ifNext("\"")) {
            ZString old = getTokenExclude("\"");
            pop();
            remove(offset(), old.getLength() + 2);
            MString key;
            key << "\"" << value << "\"";
            insert(key, offset());
         } else {
	    pop();
	    throw coreutils::Exception("Fix me to accept integer type.");
	 }
      } else {
         std::cout << "[" << unparsed() << "]" << std::endl;
         MString key;
     	   if(notfirst)
           key << ",";
         key << "\"" << path << "\":" << "\"" << value << "\"";
         insert(key, offset());
      }
   }

   ZString JString::find(ZString path) {
      if(locate(path)) {
         if(ifNext("\""))
   	     return getTokenExclude("\"");
// TODO: Handle numbers that are not in double quotes.

         if(startsWith("[")) {
            ZString temp = getContainer();
            std::cout << temp << std::endl;
         }
      }
      return ZString();
   }

   void JString::operator=(ZString &value) {
      std::cout << "operator=(ZString &)" << value << "\n";
   }

   JString& JString::operator=(const char *value) {
      std::cout << "operator=" << value << "\n";
      set(path, value);
      return *this;
   }

   // ZString JString::operator[](const char *path) {
   //    std::cout << "operator[" << path << "]\n";
   //    this->path = path;
   //    reset();
   //    return find(path);
   // }

  JString& JString::operator[](const char *path) {
     std::cout << "operator[" << path << "]\n";
     reset();
     this->path = path;
     find(path);
     return *this;
  }

   bool JString::locate(ZString path) {
      path.split(".", 1);
      notfirst = false;
      if(ifNext("{")) {
         while(startsWith("\"")) {
	    notfirst = true;
            ZString label;
            ZString value;
            if(ifNext("\"")) {
               label = getTokenExclude("\"");
               ifNext("\"");
            }  else
              throw coreutils::Exception("Labels must be contained in double quotes.");
            if(ifNext(":")) {
               if(label == path[0]) {
                  if(path.getList().size() == 1)
		    {
		       std::cout << "cursor: " << unparsed() << std::endl;
		       return true;
		    }
                  return locate(path[1]);
               } if(startsWith("\"")) {
                  getContainer();;
	       } else if(startsWith("[")) {
                  getContainer();
               } else {
                  throw coreutils::Exception("Unrecognized data type.");
               }
               ifNext(",");
            } else
              throw coreutils::Exception("Expected colon after label.");
         }
      } else if(ifNext("[")) {
         ZString label = path[0].getTokenExclude("[");
         path[0].ifNext("[");
         ZString key = path[0].getTokenExclude("=");
         path[0].ifNext("=");
         ZString value = path[0].getTokenExclude("]");
         while(!ifNext("]")) {
            push();
            ZString check = find(key);
            pop();
            if(check.equals(value)) {
               return locate(label);
            } else {
               getContainer();
               ifNext(",");
            }
         }
      }
      return false;
   }
}
