/******************************************************************************
** Copyright (C) 2001, University of Alabama in Huntsville. All rights 
** reserved.
**
** File   : CGIFSyntaxAnalyzer.cpp
**
** Author : Saranyu Tantipongsakul, Da Sun
**
** Description:
**    This file provides the implementation for CCGIFSyntaxAnalyzer class.
**
** History:
** 01-Dec-01 Saranyu Tantipongsakul, Da Sun
**     File Created.  Copied major portions from parser written in C by Da.
** 02-Dec-01 Satish Hota
**     Added a call to CRelation::SetRelDef in the install method to set the 
**     type of the relation.
******************************************************************************/
#pragma warning(disable: 4786)  // Disable debug information warning

#include "CGIFSyntaxAnalyzer.h"

CCGIFSyntaxAnalyzer::CCGIFSyntaxAnalyzer(CCGIFLexicalAnalyzer *pTokenizer)
{
	CONCEPT = 1;	// initial value for CONCEPT
	RELATION=2;		// initial value for RELATION
	COMMENT=3;		// initial value for COMMENT
	
	m_pTokenizer = pTokenizer;
	seg_ptr = m_pTokenizer->seg;
	m_nNewTokenNumber = m_pTokenizer->m_nNewTokenNumber;
    simpleTokenList = m_pTokenizer->simpleTokenList;
	
	// May throw exception
	if( !(concept = new concepttype) )  error("no enough memory");
	if( !(relation = new relationtype) ) error("No enough memory");
	
}

CCGIFSyntaxAnalyzer::~CCGIFSyntaxAnalyzer()
{
}

void CCGIFSyntaxAnalyzer::error(char *msg)
{
/*perror(msg);
    exit(0);*/
	return;
}

int CCGIFSyntaxAnalyzer::getArc(simpleTokenType *simpleTokenList, int *position, arctype *arc, int tokenNumber)
{
	if(*position < tokenNumber)
	{
		int result=0;
        char label[NAMESIZE];
        concepttype *concept;
		
        if( !(concept = new concepttype) ) error(" no enough memory");
		concept->coreflinks = NULL;
        concept->referlinks = NULL;
		
        if( getConcept(simpleTokenList, position, concept, tokenNumber) )
		{
			arc->concept = concept;
			strcpy(arc->con_bound, "concept");
			return 1;
		}
		
        else
		{
			if(getBoundLabel (simpleTokenList, position, label,tokenNumber) )
			{
				strcpy(arc->boundLabel, label);
				strcpy(arc->con_bound, "boundLabel");
				return 1;
			} else return 0;
		}    
	} 
	return 0;
}

int CCGIFSyntaxAnalyzer::getBoundLabel(simpleTokenType *simpleTokenList, int *position, char *label, int tokenNumber)
{
	if(*position < tokenNumber-1)
	{
		if(!strcmp(simpleTokenList[*position].value,"?") )
		{
			if(simpleTokenList[*position+1].kind == identifier) 
			{
				strcpy(label,simpleTokenList[*position+1].value);
				(*position) += 2;
				return 1;
			} 
			else error("Unend Bound Label\n");
		}
	}
	return 0;
}

int CCGIFSyntaxAnalyzer::getComment(simpleTokenType *simpleTokenList, int *position, char *com, int tokenNumber)
{
	strcpy(com, "");
	if(*position < tokenNumber)
	{
		int temp=*position;
        if( !strcmp(simpleTokenList[*position].value , ";") && 
			(*position < tokenNumber-1) )
		{
			if(*position < tokenNumber) 
			{
				(*position)++;
				while( strcmp(simpleTokenList[*position].value, ";") )
				{
					strcat( com, " ");
					strcat( com, simpleTokenList[*position].value);
					if(*position < tokenNumber) (*position)++;
					else error("unend comment\n");
				}
				(*position)++;
				return 1;
			} else return 0;
		}  
	} 
	return 0;
}

int CCGIFSyntaxAnalyzer::getConcept(simpleTokenType *simpleTokenList, int *position, concepttype *concept, int tokenNumber)
{
	int startPosition = *position;
	if(*position < tokenNumber)
	{
		if( (!strcmp(simpleTokenList[*position].value, "[") ) &&
			(*position < tokenNumber-1) )
		{
			if(simpleTokenList[(*position) +1].kind == identifier)
			{
				strcpy(concept->name, simpleTokenList[*position+1].value);  
				(*position) +=2;
			}
			else (*position) +=1;
			
			int flag=0;
			do
			{
				char coref[NAMESIZE];
				char type[KINDSIZE];
				
				if(flag=getCorefLinks(simpleTokenList, position, coref, 
					type, tokenNumber))
				{
					coreflinktype *coreftemp = new coreflinktype;
					coreftemp->next =NULL;
					
					strcpy( coreftemp->value, coref);
					strcpy( coreftemp->kind, type);
					
					if(concept->coreflinks == NULL) concept->coreflinks = coreftemp;
					else
					{
						coreflinktype *curr= concept->coreflinks;
						coreflinktype *next= curr->next;
						
						while(next != NULL) 
						{
							curr = curr->next;
							next = curr->next;
						}
						curr->next = coreftemp;
					}
				}
			} while(flag);
			
			flag=0;
			do 
			{
				char ref[NAMESIZE];
				if(flag=getReferent(simpleTokenList, position, ref,tokenNumber))
				{
					referenttype *reftemp;
					if( !(reftemp = new referenttype) ) error("no enough memory");
					
					reftemp->next =NULL;
					strcpy( reftemp->value, ref);
					if(flag ==1) strcpy( reftemp->kind, "name");
					if(flag ==2) strcpy( reftemp->kind, "indmaker");
					
					if(concept->referlinks == NULL) concept->referlinks = reftemp;
					else
					{
						referenttype *curr= concept->referlinks;
						referenttype *next= curr->next;
						
						while(next != NULL) 
						{
							curr = curr->next;
							next = curr->next;
						}
						curr->next = reftemp;
					}
				}
			} while(flag);
			
			char com[COMMENTSIZE];
			if(getComment (simpleTokenList, position, com, tokenNumber) )
				strcpy(concept->comment, com);
			if( !strcmp(simpleTokenList[*position].value, "]") )
			{
				(*position)++;
				return 1;
			}
		}
	} 
	
	*position = startPosition;
	return 0;
}

int CCGIFSyntaxAnalyzer::getCorefLinks(simpleTokenType *simpleTokenList, int *position, char *coref, char *type, int tokenNumber)
{
	if(*position < tokenNumber)
	{
		char label[NAMESIZE];
        if(getDefLabel(simpleTokenList, position, label, tokenNumber) )
		{
			strcpy(coref, label);
			strcpy(type,"*");
			return 1;
		}
		
        else
		{ 
			if (getBoundLabel(simpleTokenList, position, label,tokenNumber) )
			{
				strcpy(coref, label);
				strcpy(type, "?");
				return 1;
			}
			else return 0;
		}
		
	} 
	return 0;
}

int CCGIFSyntaxAnalyzer::getDefLabel(simpleTokenType *simpleTokenList, int *position, char *label, int tokenNumber)
{
	if( (*position < tokenNumber) &&
		(!strcmp(simpleTokenList[*position].value,"*")) )
	{
		if( (*position < tokenNumber-1) &&
			(simpleTokenList[*position+1].kind == identifier) )
		{
			strcpy(label,simpleTokenList[*position+1].value);
			(*position) +=2;
			return 1;
		}
		else error("unend defLabel\n");
	} 
	return 0;
}

int CCGIFSyntaxAnalyzer::getIndexIndiv(simpleTokenType *simpleTokenList, int *position, char *label, int tokenNumber)
{
	if( (*position < tokenNumber) &&
		(!strcmp(simpleTokenList[*position].value,"#")) )
	{
		if( (*position < tokenNumber-1) &&
			(simpleTokenList[*position+1].kind == identifier) )
		{
			strcpy(label,simpleTokenList[*position+1].value);
			(*position) +=2;
			return 1;
		}
		else 
		{
			strcpy(label," ");
			(*position) ++;
			return 1;
		}
	} 
	return 0;
}

int CCGIFSyntaxAnalyzer::getOneElement(simpleTokenType *simpleTokenList, int tokenNumber, concepttype *concept, relationtype *relation, char comment[], int *position)
{
	if( getConcept(simpleTokenList, position, concept, tokenNumber))    
		return 1;  //concept
	else
	{
		if( getRelation(simpleTokenList, position, relation, tokenNumber))
			return 2;   //relation
		else
		{
			if(getComment (simpleTokenList, position, comment, tokenNumber))
				return 3;   //comment
			else return 0;  //nothing
		}
	}
}

int CCGIFSyntaxAnalyzer::getReferent(simpleTokenType *simpleTokenList, int *position, char *ref, int tokenNumber)
{
	if( (*position < tokenNumber) &&
		(!strcmp(simpleTokenList[*position].value,":") ) )
	{
		if(*position < tokenNumber-1) 
		{
			if (simpleTokenList[*position+1].kind == identifier) 
			{
				strcpy(ref,simpleTokenList[*position+1].value);
				(*position) += 2;
				return 1;
			}
			
			else if( !strcmp(simpleTokenList[*position+1].value, "#") )
			{
				if( (*position < tokenNumber-2) &&  
					(simpleTokenList[*position+2].kind == identifier) )
				{
					strcpy(ref,simpleTokenList[*position+2].value);
					(*position) += 3;
					return 2;
				}
				else
				{
					strcpy(ref," ");
					(*position) +=2;
					return 2;
				}
				
			}
			else
			{
				strcpy(ref," ");
				(*position) ++;
				return 1;
			}
		}
	}
	return 0;
}

int CCGIFSyntaxAnalyzer::getRelation(simpleTokenType *simpleTokenList, int *position, relationtype *relation, int tokenNumber)
{
	int startPosition = *position;
	if( *position < tokenNumber )
	{
		if( !strcmp (simpleTokenList[*position].value, "(") &&
			(*position < tokenNumber-1) &&
			(simpleTokenList[(*position) +1].kind == identifier) )
		{
			strcpy(relation->name, simpleTokenList[*position+1].value);  
			(*position) +=2;
			
			int flag=0;
			
			do
			{
				arctype *arc;
				if( !(arc = new arctype)) error("no enough memory");
				
				if(flag=getArc(simpleTokenList, position, arc, tokenNumber) )
				{
					arclisttype *arclist;
					if( !(arclist = new arclisttype)) error(" no enough memory");
					arclist->arc = arc;
					arclist->next =NULL;
					
					if(relation->arcs == NULL) 
					{
						relation->arcs = arclist;
						(relation->arcs)->arc = arclist->arc;
					}
					
					else
					{
						arclisttype *curr= relation->arcs;
						arclisttype *next= curr->next;
						
						while(next != NULL) 
						{
							curr = curr->next;
							next = curr->next;
						}
						curr->next = arclist;
					}
				}
			} while(flag);
			
			char com[COMMENTSIZE];
			if(getComment (simpleTokenList, position, com, tokenNumber) )
				strcpy(relation->comment, com);
			
			if( !strcmp(simpleTokenList[*position].value, ")") )
			{
				(*position)++;
				return 1;
			}
		} 
	}
	
    *position = startPosition;
	return 0;
}

CKnowledgeBase* CCGIFSyntaxAnalyzer::install(ACCGFactory *pFactory)
{
	// Initialize CLIPS
	CCLPControl clipsController;
	clipsController.Initialize();
	
	//CKnowledgeBase *pKnowledge = m_pFactory->NewKnowledgeBase;
    std::cout << "Starting..." << std::endl;
	
	//-- [Knowledge Base:
	
	// Creating Knowledge Base
    std::cout << "Creating Knowledge Base" << std::endl;
    m_pKB = pFactory->NewKnowledgeBase();
	//    *KBPP = m_pKB; 
	
	//-- [TypeHierarchy:
	
	// Creating Type Hierarchy
    std::cout << "Creating Type Hierarchy" << std::endl;
	//    CTypeHierarchy* m_pTH = pFactory->NewTypeHierarchy();
	m_pTH = pFactory->NewTypeHierarchy();
    m_pKB->SetTypes(m_pTH);
	
	//	position =seg[0];
	position = *seg_ptr;
	
	int type=0;
	do 
	{
		concept->coreflinks = NULL;
        concept->referlinks = NULL;
        relation->arcs = NULL;
		strcpy(comment,"");
		
		type = getOneElement(simpleTokenList, m_nNewTokenNumber, concept, relation,
			comment,&position);
        if( (type == RELATION ) && ( !strcmp(relation->name, "GT")) &&
			(!strcmp((((((relation->arcs)->next)->arc)->concept)->referlinks)->kind, "name")) )
			
		{
            // Create Type Defintion
			std::cout << "Creating Type Definition" << std::endl;
			
			CTypeDefinition* td1 = m_pTH->FindByName( ((((relation->arcs)->
				arc)->concept)->referlinks)->value);
			
			if (!td1)
			{
				td1 = pFactory->NewTypeDefinition( ((((relation->arcs)->
					arc)->concept)->referlinks)->value);
				m_pTH->Insert(td1);
			}
			
			
			CTypeDefinition* td2 = m_pTH->FindByName( (((((relation->arcs)->next)->
				arc)->concept)->referlinks)->value);
			
			if (!td2)
			{
				td2 = pFactory->NewTypeDefinition((((((relation->arcs)->next)->
					arc)->concept)->referlinks)->value);
				m_pTH->Insert(td2);
			}
			
			td2->SetComment(relation->comment);
			td2->AddSuperclass(td1);
		}
		
		if( (type == RELATION ) && ( !strcmp(relation->name, "GT")) &&
			(!strcmp((((((relation->arcs)->next)->arc)->concept)
			->referlinks)->kind, "quant")) )
			
		{
            // Create Type Defintion
			std::cout << "Creating Type Definition" << std::endl;
			
			CTypeDefinition* td1 = m_pTH->FindByName( ((((relation->arcs)->
				arc)->concept)->referlinks)->value);
			
			if (!td1)
			{
				td1 = pFactory->NewTypeDefinition( ((((relation->arcs)->
					arc)->concept)->referlinks)->value);
				m_pTH->Insert(td1);
			}
			
			
			while( (((((((relation->arcs)->next)->arc)->concept)
				->referlinks)->quantifier)->stringlist)->value != NULL)
			{
				CTypeDefinition* td2 = m_pTH->FindByName( (((((((relation->arcs)->next)->arc)->concept)
					->referlinks)->quantifier)->stringlist)->value);
				
				if (!td2)
				{
					td2 = pFactory->NewTypeDefinition((((((((relation->arcs)->next)->arc)->concept)
						->referlinks)->quantifier)->stringlist)->value);
					m_pTH->Insert(td2);
				}
				td2->SetComment(relation->comment);
				td2->AddSuperclass(td1);
				
				((((((relation->arcs)->next)->arc)->concept)
					->referlinks)->quantifier)->stringlist = 
					(((((((relation->arcs)->next)->arc)->concept)
					->referlinks)->quantifier)->stringlist)->next;
			}  
		}
        
		if( type == COMMENT ) //it is comment
		{
            m_pTH->SetComment(comment);
		}
		
	} while ( (type ==RELATION) | (type ==COMMENT) );
	
	
    m_pTH->Commit();
	
	// Creating Relation Hierarchy
    std::cout << "Creating Relation Hierarchy" << std::endl;
	
    // -- [RelationHierarchy:
	//	CRelationHierarchy* m_pRH = pFactory->NewRelationHierarchy();
	m_pRH = pFactory->NewRelationHierarchy();
	
    m_pKB->SetRelations(m_pRH);
	
	//    position =seg[2];
	position = *(seg_ptr + 2);
	
	type=0;
	do 
	{
		concept->coreflinks = NULL;
        concept->referlinks = NULL;
        relation->arcs = NULL;
		strcpy(comment,"");
		
		type = getOneElement(simpleTokenList, m_nNewTokenNumber, concept, relation,
			comment,&position);
        if( (type == RELATION ) && ( !strcmp(relation->name, "GT")) &&
			(!strcmp((((((relation->arcs)->next)->arc)->concept)->referlinks)->kind, "name")) )
			
		{
            // Create relation Defintion
			std::cout << "Creating relation Definition" << std::endl;
			
			CRelationDefinition* td1 = m_pRH->FindByName( ((((relation->arcs)->
				arc)->concept)->referlinks)->value);
			
			if (!td1)
			{
				td1 = pFactory->NewRelationDefinition( ((((relation->arcs)->
					arc)->concept)->referlinks)->value);
				m_pRH->Insert(td1);
			}
			
			
			CRelationDefinition* td2 = m_pRH->FindByName( (((((relation->arcs)->next)->
				arc)->concept)->referlinks)->value);
			
			if (!td2)
			{
				td2 = pFactory->NewRelationDefinition((((((relation->arcs)->next)->
					arc)->concept)->referlinks)->value);
				m_pRH->Insert(td2);
			}
			
			td2->SetComment(relation->comment);
			td2->AddSuperclass(td1);
		}
		
		if( (type == RELATION ) && ( !strcmp(relation->name, "GT")) &&
			(!strcmp((((((relation->arcs)->next)->arc)->concept)
			->referlinks)->kind, "quant")) )
			
		{
            // Create relation Defintion
			std::cout << "Creating relation Definition" << std::endl;
			
			CRelationDefinition* td1 = m_pRH->FindByName( ((((relation->arcs)->
				arc)->concept)->referlinks)->value);
			
			if (!td1)
			{
				td1 = pFactory->NewRelationDefinition( ((((relation->arcs)->
					arc)->concept)->referlinks)->value);
				m_pRH->Insert(td1);
			}
			
			
			while( (((((((relation->arcs)->next)->arc)->concept)
				->referlinks)->quantifier)->stringlist)->value != NULL)
			{
				CRelationDefinition* td2 = m_pRH->FindByName( (((((((relation->arcs)->next)->arc)->concept)
					->referlinks)->quantifier)->stringlist)->value);
				
				if (!td2)
				{
					td2 = pFactory->NewRelationDefinition((((((((relation->arcs)->next)->arc)->concept)
						->referlinks)->quantifier)->stringlist)->value);
					m_pRH->Insert(td2);
				}
				td2->SetComment(relation->comment);
				td2->AddSuperclass(td1);
				
				((((((relation->arcs)->next)->arc)->concept)
					->referlinks)->quantifier)->stringlist = 
					(((((((relation->arcs)->next)->arc)->concept)
					->referlinks)->quantifier)->stringlist)->next;
			}  
		}
        
		if( type == COMMENT ) //it is comment
		{
            m_pRH->SetComment(comment);
		}
		
	} while ( (type ==RELATION) | (type ==COMMENT) );
	
    m_pRH->Commit();
	
	
    // Creating Catalog Of Individuals
	
    std::cout << "Creating COI" << std::endl;
	
    // -- [CatalogOfIndividuals:
    
	//	CCatalogOfIndividuals* coi = pFactory->NewCatalogOfIndividuals();
	m_pCOI = pFactory->NewCatalogOfIndividuals();
	
    m_pKB->SetCOI(m_pCOI);
	
	//    position =seg[4];
	position = *(seg_ptr + 4);
	
	type=0;
	do 
	{
		concept->coreflinks = NULL;
        concept->referlinks = NULL;
        relation->arcs = NULL;
		strcpy(comment,"");
		
		type = getOneElement(simpleTokenList, m_nNewTokenNumber, concept, relation,
			comment,&position);
        if( type == CONCEPT ) //it is CONCEPT
		{
			CTypeDefinition *pTypeDef = m_pTH->FindByName( concept->name);
			
			if (!pTypeDef)
			{
				pTypeDef = pFactory->NewTypeDefinition(concept->name);
				m_pTH->Insert(pTypeDef);
				pTypeDef->Commit();
			}
			
            CConcept *con = pFactory->NewConcept();
            con->SetName("");   // Need to check for name in COI area
			con->SetTypeDef(pTypeDef);
			char strtmp[100];
			strcpy(strtmp,"#");
			strcat(strtmp, (concept->referlinks)->value);
			con->SetIndividualMarker(strtmp);
            m_pCOI->Insert(con);
		}
		
		if( type == COMMENT ) //it is comment
		{
            m_pCOI->SetComment(comment);
		}
		
	} while ( (type ==CONCEPT) | (type ==COMMENT) );
	
	
	const CCatalogOfIndividuals::IndividualMap* pmapIndividual = m_pCOI->GetIndividuals();
    CCatalogOfIndividuals::IndividualMap::const_iterator iterIndividual;
	
	iterIndividual = pmapIndividual->begin();
	while ( iterIndividual != pmapIndividual->end())
	{
		CConcept *theConcept = (*iterIndividual).second;
		std::cout << "[" << theConcept->GetTypeDef()->GetTypeName() << ":" << theConcept->GetIndividualMarker() << "]" << std::endl;
		iterIndividual++;
	}
	
	// Creating Sheet Of Assertion
    std::cout << "Creating Sheet Of Assertion" << std::endl;
	
    
    // -- [Assertion:
	
	//	CSheetOfAssertion* soa = pFactory->NewSheetOfAssertion();
	m_pSOA = pFactory->NewSheetOfAssertion();
	
    m_pKB->SetSOA(m_pSOA);
	
	//	position =seg[6];
	position = *(seg_ptr + 6);
	
	type=0;
	do 
	{
		concept->coreflinks = NULL;
        concept->referlinks = NULL;
        relation->arcs = NULL;
		strcpy(comment,"");
		
		type = getOneElement(simpleTokenList, m_nNewTokenNumber, concept, relation,
			comment,&position);
        if( type == RELATION ) //it is RELATION
		{
			CRelationDefinition *pRelType = m_pRH->FindByName(relation->name);
			
			if (!pRelType)
			{
				pRelType = pFactory->NewRelationDefinition(relation->name);
				m_pRH->Insert(pRelType);
				pRelType->Commit();
			}
			
			CRelation *rel1 = pFactory->NewRelation();
			rel1->SetRelDef(pRelType); 
			while( relation->arcs != NULL)
			{
				if( !strcmp( ((relation->arcs)->arc)->con_bound, "concept") )
				{
					
					if( ((((relation->arcs)->arc)->concept)->referlinks) && 
						!strcmp( ((((relation->arcs)->arc)->concept)->referlinks)->kind, "indmaker") )
					{
						char strtmp[100];
						strcpy(strtmp,"#");
						strcat(strtmp, ((((relation->arcs)->arc)->concept)->referlinks)->value);
						
						
						
                        CConcept* arc1 = m_pCOI->FindByMarker(strtmp);
                        m_pSOA->Insert(arc1);
						rel1->AddArc(arc1);
					}
					else
					{
						
						CTypeDefinition *pArcType = m_pTH->FindByName( (((relation->arcs)->arc)->
								concept)->name);
						
						if (!pArcType)
						{
							pArcType = pFactory->NewTypeDefinition( (((relation->arcs)->arc)->
								concept)->name);
							m_pTH->Insert(pArcType);
							pArcType->Commit();
						}
						CConcept *arc = pFactory->NewConcept();

						if( ((((relation->arcs)->arc)->concept)->referlinks) && 
							!strcmp( ((((relation->arcs)->arc)->concept)->referlinks)->kind, "name") )
						{
							arc->SetName( ((((relation->arcs)->arc)->
								concept)->referlinks)->value );
						}

						arc->SetTypeDef(pArcType);
						m_pSOA->Insert(arc);
						rel1->AddArc(arc);
					}	
				}
                relation->arcs = relation->arcs->next;
			}
			
            m_pSOA->Insert(rel1);
        }
		
	} while ( type !=0 );
	
    // -- (ATTR [Block:#1] [Color:'Red'] ;Block #1 is red;)
    // -- (OnTable [Block:#1] [Location:#5])
    
	
	// Some more testing
	std::cout << "Finding By UID" << std::endl;
	ACConstruct* construct1 = ACConstruct::FindByUid(5);
	
	std::cout << "Opening CLIPS shell" << std::endl;
    //clpcontrol.shell();
	
	std::cout << "Finished!!!" << std::endl;
	
	return m_pKB;
}
