/* Dialect - Code Output Formatter
 * Copyright (C) 2001-2002  Jay Freeman (saurik)
*/

/*
 *        Redistribution and use in source and binary
 * forms, with or without modification, are permitted
 * provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer in the documentation
 *    and/or other materials provided with the
 *    distribution.
 * 3. The name of the author may not be used to endorse
 *    or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef DIALECT_MCPPDIALECT_H
#define DIALECT_MCPPDIALECT_H

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "dialect/dialect.h"
#include "dialect/IDialect.h"
#include "dialect/DialectImpl.h"
#include "ilengineer/Operation.h"

namespace Dialect {

	DIAPEXIS_CLASS MCppDialect :
		public DialectImpl<IDialect>
	{

		DIAPEXIS_OBJECT(MCppDialect)

		DIAPEXIS_QUERY_BEGIN(MCppDialect)
        DIAPEXIS_QUERY_MAP(Diapexis::Unknown)
		DIAPEXIS_QUERY_MAP(IDialect)
		DIAPEXIS_QUERY_END()

	  public:
		MCppDialect() {}

		using DialectImpl<IDialect>::Render;
		void Render(const Metallurgy::Value *value, std::wstring &builder);

		void Perform(const Metallurgy::Element *element, std::wstring &builder, Metallurgy::ModDeque &mods);
		void Formulate(Metallurgy::Property *property);
		void Formulate(Metallurgy::Method *method);
		void Formulate(const std::wstring &str);
		void Formulate(wchar_t chr);
		void Formulate(ILEngineer::Operation *op);
		void Formulate(ILEngineer::Statement *st);
		void Formulate(Metallurgy::Attribute *attr);

		void Formulate(const Metallurgy::Element *element) {
			std::wstring builder;
			Render(element, builder);
			*wout << builder;
		}

		/*void Formulate(Metallurgy::MetaMethod &method);
		void Formulate(const Metallurgy::MetaElement &element);
		void Formulate(ILEngineer::Operation *op);
		void Formulate(ILEngineer::Statement *st);
		void Formulate(const std::wstring &str);
		void Formulate(Metallurgy::MetaProperty &property);
		void Formulate(Metallurgy::Attribute &attr);*/

		void Formulate(Metallurgy::Field &field) {
			*wout << GetIndent();

			switch (field.getAccess()) {
				case Chordata::Flags::fdPublic:
					*wout << L"public ";
					break;
				case Chordata::Flags::fdPrivate:
					*wout << L"private ";
					break;
				case Chordata::Flags::fdFamily:
					*wout << L"protected ";
					break;
			}

			if (field.IsStatic())
				*wout << L"static ";

			Formulate(field.getElement());
			*wout << L' ' << field.getName().getFull() << L';' << std::endl;
		}

		virtual void Formulate(const Metallurgy::TypeDef &type) {
			//if (type.getShortName() != L"ConnectStream") return *this;
			/**wout << GetIndent() << L"namespace " << type.getName().getSpace() << L" {" << std::endl;

			UpIndent();

			Metallurgy::TokenList tkAttrs = type.getAttributes();
			for (int i(0); i < tkAttrs.size(); i++)
				Formulate(dynamic_cast<Metallurgy::Attribute *>(tkAttrs[i]));

			*wout << GetIndent();

			if (type.isPublic())
				*wout << L"public ";

			if (type.getSemantics() == Chordata::Flags::tdInterface)
				*wout << L"interface ";
			else {
				std::wstring extends = type.getName().getFull();
				if (
			}
				
			else if (type.isClass())
				*wout << L"class ";
			else if (type.isValueType())
				*wout << L"struct ";
			else {
				std::cerr << "Ummm... Magic?" << std::endl;
				exit(1);
			}

			*wout << type.getShortName();

			Metallurgy::TokenList tkImpls = type.getInterfaces();

			bool isExtended(false);
			if (RidFromToken(type.getExtends()) && type.getExtends() != 0x01000001 /* 16777217 = System.Object *//*) {
				isExtended = true;
				*wout << L" : " << m_Import->getTypeName(type.getExtends());
			}

			for (Metallurgy::TokenList::iterator tkI = tkImpls.begin(); tkI != tkImpls.end(); tkI++, isExtended = true)
				*wout << (isExtended ? L", " : L" : ") <<  m_Import->getTypeName(m_Import->openImplement(*tkI).getInterface());

			/*COR_FIELD_OFFSET    *rFieldOffset = NULL;
			ULONG               cFieldOffset = 0;
			mdImport->GetClassLayout(tdToken, NULL, rFieldOffset, 0, &cFieldOffset, NULL);*//*

			*wout << L" {" << std::endl;

			UpIndent();

			Metallurgy::TokenList tkFields(type.getFields());
			Metallurgy::TokenList tkMethods(type.getMethods());
			Metallurgy::TokenList tkProperties(type.getProperties());

			for (Metallurgy::TokenList::iterator tkI = tkFields.begin(); tkI != tkFields.end(); tkI++)
				Formulate(m_Import->openField(*tkI));

			for (Metallurgy::TokenList::iterator tkI = tkProperties.begin(); tkI != tkProperties.end(); tkI++) {
				Metallurgy::MetaProperty &property(m_Import->openProperty(*tkI));
				Formulate(property);

				mdToken get = property.getGetter(), set = property.getSetter();
				for (Metallurgy::TokenList::iterator tkI = tkMethods.begin(); tkI != tkMethods.end(); tkI++)
					if ((*tkI) == get || (*tkI) == set)
						tkMethods.erase(tkI--);
			}

			for (Metallurgy::TokenList::iterator tkI = tkMethods.begin(); tkI != tkMethods.end(); tkI++)
				Formulate(m_Import->openMethod(*tkI));

			DownIndent();
			*wout << GetIndent() << L"}" << std::endl;

			DownIndent();
			*wout << L"}" << std::endl << std::endl;*/
		}
	};

}

#endif//DIALECT_MCPPDIALECT_H