#include <swilib.h>
#include "main.h"
#include "string_util.h"
#include "xml_parser.h"

int IsSpace (char c){
	return	c == ' ' || c == '\n' || c == '\r' || c == '\t';
}

int IsLit (char c){
  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

int IsNum (char c){
	return (c >= '0' && c <= '9');
}

int InName (char c){
  return IsLit(c) || IsNum(c) || c == '_' || c == '-' || c == ':';
}


 XMLNode *XMLTree=0;
 XMLAttr *curattr=0;
 int *TreeBranchs;
 int BranchPos=0;
 XMLNode *current = 0;
 XMLNode *tmp=0;
 XMLAttr *attribs=0;
 int isClosed=0;
 char *TagName;					
 char *AttrName;				
 char *AttrValue;				
 char *Text;
 int TagState;
 int MSState;

 int f;
 unsigned int ul;

 char _crlf[2] = {0xd,0xa};
 char tabul[100];
 char bbuf[256];
 char bbf[256];

 
void SaveBranch(XMLNode *tmpp){
 while(tmpp){
   strcpy(bbuf,tabul);
   sprintf(bbf,"name: %s = ",tmpp->name);
   strcat(bbuf,bbf);
   if(tmpp->value){
     sprintf(bbf,"%s",tmpp->value);
     strcat(bbuf,bbf);
   }
   strcat(bbuf,_crlf);
   _write(f,bbuf,strlen(bbuf),&ul);
   if(tmpp->attr){
     XMLAttr *ta=tmpp->attr;
     strcpy(bbuf,tabul);
     strcat(bbuf,"attributes: ");
     strcat(bbuf,_crlf);
     _write(f,bbuf,strlen(bbuf),&ul);
     while(ta){
       strcpy(bbuf,tabul);
       sprintf(bbf,"%s - ",ta->name);
       strcat(bbuf,bbf);
       if(ta->param){
         sprintf(bbf,"%s",ta->param);
         strcat(bbuf,bbf);
       }
       strcat(bbuf,_crlf);
       _write(f,bbuf,strlen(bbuf),&ul);
       ta=ta->next;
     }
   }
   _write(f,_crlf,2,&ul);
   if(tmpp->subnode){
     strcat(tabul,"  ");
     SaveBranch(tmpp->subnode);
     *(tabul+strlen(tabul)-2)=0;
   }
   tmpp=tmpp->next;
 }
}

void SaveTree(XMLNode *tree){
  //strcpy(tabul,"");
  zeromem(tabul,64);
#ifdef NEWSGOLD
  const char savepath[]="4:\\xml_packet.txt";
#else
  const char savepath[]="0:\\xml_packet.txt";
#endif
  f=_open(savepath, A_ReadWrite+A_Create+A_Append+A_BIN,P_READ+P_WRITE,&ul);
  SaveBranch(XMLTree);
  _close(f,&ul);
}
 
void EndTag(void){
  if((TagState == TS_NORMAL)||(TagState == TS_EMPTY)){
    tmp=malloc(sizeof(XMLNode));
    zeromem(tmp,sizeof(XMLNode));
    if (!XMLTree){
      XMLTree=tmp;
    }else{
      if(!isClosed)current->next=tmp;
      else current->subnode=tmp;
    }
    tmp->name=malloc(strlen(TagName)+1);
    if(attribs)tmp->attr=attribs;
    attribs=0;
    strcpy(tmp->name,TagName);
    *(TreeBranchs+BranchPos)=(int)tmp;
    BranchPos++;
    current=tmp;
    curattr=0;
    isClosed=1;
  }
  if((TagState == TS_EMPTY)||(TagState == TS_CLOSE)){
    if(BranchPos>0){
      BranchPos--;
      current=(void*)(*(TreeBranchs+BranchPos));
    }
    isClosed=0;
  }
}

void EndAttr(void){
  XMLAttr *tmp2=malloc(sizeof(XMLAttr));
  zeromem(tmp2,sizeof(XMLAttr));
  tmp2->name=malloc(strlen(AttrName)+1);
  strcpy(tmp2->name,AttrName);
  if(strlen(AttrValue)>0){
    char *newattrval = Replace_Special_Syms(AttrValue);
   tmp2->param=malloc(strlen(newattrval)+1);
   strcpy(tmp2->param,newattrval);
   mfree(newattrval);
  }
  if(!curattr){
    attribs=tmp2;
  }else{
    curattr->next=tmp2;
  }
  curattr=tmp2;
}

void DestroyTree(XMLNode *tmpp){
 while(tmpp){
   XMLAttr *ta=tmpp->attr;
   while(ta){
       tmpp->attr=ta->next;
       if(ta->name)mfree(ta->name);
       if(ta->param)mfree(ta->param);
       mfree(ta);
       ta=tmpp->attr;
   }
   if(tmpp->subnode){
     DestroyTree(tmpp->subnode);
   }
   XMLNode *tmpp2=tmpp->next;
   if(tmpp->name)mfree(tmpp->name);
   if(tmpp->value)mfree(tmpp->value);
   mfree(tmpp);
   tmpp=tmpp2;
 }
 
 XMLTree=0;
 curattr=0;
 BranchPos=0;
 current = 0;
 tmp=0;
 attribs=0;
 isClosed=0; 
}

void Finish(void){
 mfree(TagName);
 mfree(AttrName);
 mfree(AttrValue);
 mfree(Text);
 mfree(TreeBranchs);
}

void *XMLDecode(char *buf, int size){

 
 TagName=malloc(size);					
 AttrName=malloc(size);				
 AttrValue=malloc(size);				
 Text=malloc(size);
 TreeBranchs=malloc(1024);

 zeromem(TagName,size);
 zeromem(AttrName,size);
 zeromem(AttrValue,size);
 zeromem(Text,size);
 MSState = MS_BEGIN;
 TagState = TS_INDEFINITE;
 char sh_str[2]=".\0";
 int i = 0;

	while ((i<size)){
            char c = *(buf+i);
            sh_str[0]=c;
            
	    switch (MSState){
		case MS_BEGIN:
			if (c == '<'){
				MSState = MS_BEGINTAG;
			}else if (!IsSpace (c)){
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_BEGINTAG:
                        strcpy(AttrName,"");
			if (IsLit (c)){
				MSState = MS_TAGNAME;
				TagState = TS_NORMAL;
                                strcpy(TagName,sh_str);

			}else if (IsSpace(c)){
				MSState = MS_MIDDLETAG;
				TagState = TS_NORMAL;
			}else if (c == '?'){
				TagState = TS_DECLARATION;
				MSState = MS_MIDDLETAG;
			}else if (c == '/'){
				TagState = TS_CLOSE;
				MSState = MS_MIDDLETAG;
			}else{
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_MIDDLETAG:
			if (IsLit (c)){
				MSState = MS_TAGNAME;
				strcpy(TagName,sh_str);
			}else if (!IsSpace (c)){
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_TAGNAME:
			if (InName (c)){
				strcat(TagName,sh_str);
			}else if (IsSpace(c)){
				MSState = MS_ENDTAGNAME;
			}else if (c == '/'){
				MSState = MS_ENDTAG;
				TagState = TS_EMPTY;
			}else if (c == '>'){
				MSState = MS_TEXT;
				EndTag();
			}else{
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_ENDTAGNAME:
			if (IsLit (c)){
				MSState = MS_ATTRIBNAME;
				strcpy(AttrName,sh_str);
			}else if (c == '/'){
				MSState = MS_ENDTAG;
				TagState = TS_EMPTY;
			}else if (c == '>'){
				MSState = MS_TEXT;
				EndTag();
			}else if (!IsSpace(c) && (c != '?' && TagState != TS_DECLARATION)){
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_ATTRIBNAME:
			if (InName(c)){
				strcat(AttrName,sh_str);
			}else if (c == '='){
				MSState = MS_ENDEQUALLY;
			}else if (IsSpace(c)){
				MSState = MS_ENDATTRIBNAME;
			}else{
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

                case MS_ENDATTRIBNAME:
			if (c == '='){
				MSState = MS_ENDEQUALLY;
			}else if (!IsSpace(c)){
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_ENDEQUALLY:
			if ((c == '\"')||(c == '\'')){
				MSState = MS_ATTRIBVALUE;
				strcpy(AttrValue,"");
			}else if (!IsSpace(c)){
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_ATTRIBVALUE:
			if ((c == '\"')||(c == '\'')){
				MSState = MS_ENDTAGNAME;
				EndAttr();
			}else{
				strcat(AttrValue,sh_str);
			}
			break;

		case MS_ENDTAG:
			if (c == '>'){
				MSState = MS_TEXT;
				EndTag();
			}else{
				Finish();
				return XMLTree;//0;
                                //EndParse = 1;
			}
			break;

		case MS_TEXT:

			if (c == '<'){
                          if(strlen(Text)>0){
                            //tmp->value=malloc(strlen(Text)+1);
                            //strcpy(tmp->value,Text);
                            tmp->value = Replace_Special_Syms(Text);
                          }
                          strcpy(Text,"");
                          MSState = MS_BEGINTAG;
                          TagState = TS_INDEFINITE;
			}else{
                          if((TagState == TS_NORMAL)) strcat(Text,sh_str);
                        }
			break;
		}
            i++;
	}

	//if (!EndParse) return 1;
        //{
//		Success();
//	}

	Finish();
        return XMLTree;//
}


/*
  Получить значение атрибута по его имени
IN: char* req_attr_name - название атрибута
    XMLAttr* attr_list  - список атрибутов тега
OUT: значение атрибута или NULL
*/
char* XML_Get_Attr_Value(char* req_attr_name, XMLAttr* attr_list)
{
  XMLAttr* attr_Ex = attr_list;
  while(attr_Ex)
  {
    if(attr_Ex->name)
      if(!strcmp(req_attr_name, attr_Ex->name)) return attr_Ex->param;
    attr_Ex = attr_Ex->next;
  }
  return NULL;
}

/*
  Получить дочерний узел из списка дочерних узлов по его имени
IN: XMLNode* node         - родительский узел
    char* req_node_name   - имя требуемого узла
OUT: дочерний узел или NULL
*/
XMLNode* XML_Get_Child_Node_By_Name(XMLNode* node, char* req_node_name)
{
  XMLNode* nodeEx = node->subnode;
  while(nodeEx)
  {
    if(nodeEx->name)
      if(!strcmp(req_node_name, nodeEx->name)) return nodeEx;
    nodeEx = nodeEx->next;
  }
  return NULL;
}

/*
  Получить дочерний узел из списка дочерних узлов по его имени,
  при условии, что существует заданный атрибут с заданным значением
IN: XMLNode* node         - родительский узел
    char* req_node_name   - имя требуемого узла
    char* req_attr_name   - имя атрибута
    char* req_attr_velue  - значение атрибута
OUT: дочерний узел или NULL
*/
XMLNode* XML_Get_Child_Node_By_Name_And_Attr(XMLNode* node, char* req_node_name, char* req_attr_name, char* req_attr_velue)
{
  XMLNode* nodeEx = node->subnode;
  while(nodeEx)
  {
    if(nodeEx->name)
      if(!strcmp(req_node_name, nodeEx->name))    // Если найден нод с нужным именем
      {
        char *attr_val = XML_Get_Attr_Value(req_attr_name, nodeEx->attr);
        if(attr_val)    // Если есть требуемый атрибут
        {
          if(!strcmp(attr_val, req_attr_velue))return nodeEx;          
        }
      }
    nodeEx = nodeEx->next;
  }
  return NULL;
}
//EOL,EOF
