/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/

#include <precomp.h>
#include "pe_class.hxx"


// NOT FULLY DECLARED SERVICES
#include <cosv/tpl/tpltools.hxx>
#include <ary/cpp/c_gate.hxx>
#include <ary/cpp/c_class.hxx>
#include <ary/cpp/c_namesp.hxx>
#include <ary/cpp/cp_ce.hxx>
#include <all_toks.hxx>
#include "pe_base.hxx"
#include "pe_defs.hxx"
#include "pe_enum.hxx"
#include "pe_tydef.hxx"
#include "pe_vafu.hxx"
#include "pe_ignor.hxx"


namespace cpp {

// using ary::Cid;

PE_Class::PE_Class(Cpp_PE * i_pParent )
	:   Cpp_PE(i_pParent),
		pStati( new PeStatusArray<PE_Class> ),
		// pSpBase,
		// pSpTypedef,
		// pSpVarFunc,
		// pSpIgnore,
		// pSpuBase,
		// pSpuTypedef,
		// pSpuVarFunc,
		// pSpuUsing,
        // pSpuIgnoreFailure,
		// sLocalName,
		eClassKey(ary::cpp::CK_class),
		pCurObject(0),
        // aBases,
		eResult_KindOf(is_declaration)
{
	Setup_StatusFunctions();

	pSpBase     = new SP_Base(*this);
	pSpTypedef  = new SP_Typedef(*this);
	pSpVarFunc  = new SP_VarFunc(*this);
	pSpIgnore   = new SP_Ignore(*this);
	pSpDefs     = new SP_Defines(*this);

	pSpuBase	= new SPU_Base(*pSpBase, 0, &PE_Class::SpReturn_Base);
	pSpuTypedef	= new SPU_Typedef(*pSpTypedef, 0, 0);
	pSpuVarFunc = new SPU_VarFunc(*pSpVarFunc, 0, 0);

	pSpuTemplate= new SPU_Ignore(*pSpIgnore, 0, 0);
	pSpuUsing   = new SPU_Ignore(*pSpIgnore, 0, 0);
    pSpuIgnoreFailure
                = new SPU_Ignore(*pSpIgnore, 0, 0);
	pSpuDefs	= new SPU_Defines(*pSpDefs, 0, 0);
}


PE_Class::~PE_Class()
{
}

void
PE_Class::Call_Handler( const cpp::Token &	i_rTok )
{
	pStati->Cur().Call_Handler(i_rTok.TypeId(), i_rTok.Text());
}

Cpp_PE *
PE_Class::Handle_ChildFailure()
{
    SetCurSPU(pSpuIgnoreFailure.Ptr());
    return &pSpuIgnoreFailure->Child();
}

void
PE_Class::Setup_StatusFunctions()
{
	typedef CallFunction<PE_Class>::F_Tok	F_Tok;

	static F_Tok stateF_start[] =			{ &PE_Class::On_start_class,
											  &PE_Class::On_start_struct,
											  &PE_Class::On_start_union };
	static INT16 stateT_start[] =       	{ Tid_class,
											  Tid_struct,
											  Tid_union };

	static F_Tok stateF_expectName[] = 		{ &PE_Class::On_expectName_Identifier,
											  &PE_Class::On_expectName_SwBracket_Left,
											  &PE_Class::On_expectName_Colon
											};
	static INT16 stateT_expectName[] = 		{ Tid_Identifier,
											  Tid_SwBracket_Left,
											  Tid_Colon
											};

	static F_Tok stateF_gotName[] =			{ &PE_Class::On_gotName_SwBracket_Left,
											  &PE_Class::On_gotName_Semicolon,
											  &PE_Class::On_gotName_Colon };
	static INT16 stateT_gotName[] =       	{ Tid_SwBracket_Left,
											  Tid_Semicolon,
											  Tid_Colon };

	static F_Tok stateF_bodyStd[] =			{ &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_ClassKey,
											  &PE_Class::On_bodyStd_ClassKey,
											  &PE_Class::On_bodyStd_ClassKey,

											  &PE_Class::On_bodyStd_enum,
											  &PE_Class::On_bodyStd_typedef,
											  &PE_Class::On_bodyStd_public,
											  &PE_Class::On_bodyStd_protected,
											  &PE_Class::On_bodyStd_private,

											  &PE_Class::On_bodyStd_template,
											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_friend,
											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,

											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,

											  &PE_Class::On_bodyStd_using,
											  &PE_Class::On_bodyStd_SwBracket_Right,
											  &PE_Class::On_bodyStd_VarFunc,
                                              &PE_Class::On_bodyStd_DefineName,
                                              &PE_Class::On_bodyStd_MacroName,

											  &PE_Class::On_bodyStd_VarFunc,
											  &PE_Class::On_bodyStd_VarFunc,
                                              &PE_Class::On_bodyStd_VarFunc, };

	static INT16 stateT_bodyStd[] =       	{ Tid_Identifier,
											  Tid_operator,
											  Tid_class,
											  Tid_struct,
											  Tid_union,

											  Tid_enum,
											  Tid_typedef,
											  Tid_public,
											  Tid_protected,
											  Tid_private,

											  Tid_template,
											  Tid_virtual,
											  Tid_friend,
											  Tid_Tilde,
											  Tid_const,

											  Tid_volatile,
											  Tid_static,
											  Tid_mutable,
					  						  Tid_inline,
											  Tid_explicit,

											  Tid_using,
											  Tid_SwBracket_Right,
											  Tid_DoubleColon,
                                              Tid_typename,
                                              Tid_DefineName,

                                              Tid_MacroName,
											  Tid_BuiltInType,
											  Tid_TypeSpecializer };

											  static F_Tok stateF_inProtection[] = 	{ &PE_Class::On_inProtection_Colon };
	static INT16 stateT_inProtection[] =   	{ Tid_Colon };

	static F_Tok stateF_afterDecl[] = 	    { &PE_Class::On_afterDecl_Semicolon };
	static INT16 stateT_afterDecl[] =   	{ Tid_Semicolon };

	SEMPARSE_CREATE_STATUS(PE_Class, start, Hdl_SyntaxError);
	SEMPARSE_CREATE_STATUS(PE_Class, expectName, Hdl_SyntaxError);
	SEMPARSE_CREATE_STATUS(PE_Class, gotName, On_gotName_Return2Type);
	SEMPARSE_CREATE_STATUS(PE_Class, bodyStd, Hdl_SyntaxError);
	SEMPARSE_CREATE_STATUS(PE_Class, inProtection, Hdl_SyntaxError);
	SEMPARSE_CREATE_STATUS(PE_Class, afterDecl, On_afterDecl_Return2Type);

#if 0
	static F_Tok stateF_inFriend[] =	 	{ On_inFriend_class,
											  On_inFriend_struct,
											  On_inFriend_union };
											  // Default: On_inFriend_Function
	static INT16 stateT_inFriend[] =     	{ Tid_class,
											  Tid_struct,
											  Tid_union };
#endif // 0
}

void
PE_Class::InitData()
{
	pStati->SetCur(start);
	sLocalName.clear();
	eClassKey = ary::cpp::CK_class;
	pCurObject = 0;
    csv::erase_container(aBases);
    eResult_KindOf = is_declaration;
}

void
PE_Class::TransferData()
{
	pStati->SetCur(size_of_states);
}

void
PE_Class::Hdl_SyntaxError( const char * i_sText)
{
    if ( *i_sText == ';' )
    {
     	Cerr() << Env().CurFileName() << ", line "
                  << Env().LineCount()
                  << ": Sourcecode warning: ';' as a toplevel declaration is deprecated."
                  << Endl();
    	SetTokenResult(done,stay);
        return;
    }

	StdHandlingOfSyntaxError(i_sText);
}

void
PE_Class::Init_CurObject()
{
    // KORR_FUTURE
    //   This will have to be done before parsing base classes, because of
    //   possible inline documentation for base classes.
	pCurObject = & Env().AryGate().Ces().Store_Class( Env().Context(), sLocalName, eClassKey );

  	for ( PE_Base::BaseList::const_iterator it = aBases.begin();
		  it !=  aBases.end();
		  ++it )
	{
		pCurObject->Add_BaseClass( *it );
	}  // end for

    Dyn< StringVector >
            pTplParams( Env().Get_CurTemplateParameters() );
    if ( pTplParams )
    {
      	for ( StringVector::const_iterator it = pTplParams->begin();
	    	  it !=  pTplParams->end();
		      ++it )
    	{
	    	pCurObject->Add_TemplateParameterType( *it, ary::cpp::Type_id(0) );
    	}  // end for
    }
}

void
PE_Class::SpReturn_Base()
{
	aBases = pSpuBase->Child().Result_BaseIds();
	pStati->SetCur(gotName);
}

void
PE_Class::On_start_class( const char * )
{
	SetTokenResult(done, stay);
	pStati->SetCur(expectName);
	eClassKey = ary::cpp::CK_class;
}

void
PE_Class::On_start_struct( const char * )
{
	SetTokenResult(done, stay);
	pStati->SetCur(expectName);
	eClassKey = ary::cpp::CK_struct;
}

void
PE_Class::On_start_union( const char * )
{
	SetTokenResult(done, stay);
	pStati->SetCur(expectName);
	eClassKey = ary::cpp::CK_union;
}

void
PE_Class::On_expectName_Identifier( const char * i_sText )
{
	SetTokenResult(done, stay);
	pStati->SetCur(gotName);
    sLocalName = i_sText;
}

void
PE_Class::On_expectName_SwBracket_Left( const char * )
{
	SetTokenResult(done, stay);
	pStati->SetCur(bodyStd);

    sLocalName = "";
	Init_CurObject();
    sLocalName = pCurObject->LocalName();

    Env().OpenClass(*pCurObject);
}

void
PE_Class::On_expectName_Colon( const char * )
{
	pStati->SetCur(gotName);
    sLocalName = "";

	pSpuBase->Push(done);
}

void
PE_Class::On_gotName_SwBracket_Left( const char * )
{
	SetTokenResult(done, stay);
	pStati->SetCur(bodyStd);

	Init_CurObject();
    if ( sLocalName.empty() )
        sLocalName = pCurObject->LocalName();

    Env().OpenClass(*pCurObject);
}

void
PE_Class::On_gotName_Semicolon( const char * )
{
	SetTokenResult(not_done, pop_success);

	eResult_KindOf = is_predeclaration;
}

void
PE_Class::On_gotName_Colon( const char * )
{
	pSpuBase->Push(done);
}

void
PE_Class::On_gotName_Return2Type( const char * )
{
	SetTokenResult(not_done, pop_success);

	eResult_KindOf = is_qualified_typename;
}

void
PE_Class::On_bodyStd_VarFunc( const char * )
{
    pSpuVarFunc->Push(not_done);
}

void
PE_Class::On_bodyStd_ClassKey( const char * )
{
	pSpuVarFunc->Push(not_done);		// This is correct,
                                        //   classes are parsed via PE_Type.
}

void
PE_Class::On_bodyStd_enum( const char * )
{
	pSpuVarFunc->Push(not_done);		// This is correct,
                                        //   enums are parsed via PE_Type.
}

void
PE_Class::On_bodyStd_typedef( const char * )
{
    pSpuTypedef->Push(not_done);
}

void
PE_Class::On_bodyStd_public( const char * )
{
    SetTokenResult(done, stay);
    pStati->SetCur(inProtection);

    Env().SetCurProtection(ary::cpp::PROTECT_public);
}

void
PE_Class::On_bodyStd_protected( const char * )
{
    SetTokenResult(done, stay);
    pStati->SetCur(inProtection);

    Env().SetCurProtection(ary::cpp::PROTECT_protected);
}

void
PE_Class::On_bodyStd_private( const char * )
{
    SetTokenResult(done, stay);
    pStati->SetCur(inProtection);

    Env().SetCurProtection(ary::cpp::PROTECT_private);
}

void
PE_Class::On_bodyStd_template( const char * )
{
    pSpuTemplate->Push(done);
}

void
PE_Class::On_bodyStd_friend( const char * )
{
    // KORR_FUTURE
    pSpuUsing->Push(done);
}

void
PE_Class::On_bodyStd_using( const char * )
{
    pSpuUsing->Push(done);
}

void
PE_Class::On_bodyStd_SwBracket_Right( const char * )
{
    SetTokenResult(done, stay);
    pStati->SetCur(afterDecl);

    Env().CloseClass();
}

void
PE_Class::On_bodyStd_DefineName(const char * )
{
	pSpuDefs->Push(not_done);
}

void
PE_Class::On_bodyStd_MacroName(const char * )
{
	pSpuDefs->Push(not_done);
}


void
PE_Class::On_inProtection_Colon( const char * )
{
    SetTokenResult(done, stay);
    pStati->SetCur(bodyStd);
}

void
PE_Class::On_afterDecl_Semicolon( const char * )
{
	SetTokenResult(not_done, pop_success);
	eResult_KindOf = is_declaration;
}

void
PE_Class::On_afterDecl_Return2Type( const char * )
{
	SetTokenResult(not_done, pop_success);
	eResult_KindOf = is_implicit_declaration;
}


}   // namespace cpp




