/* 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.
*/

#include "stdafx.h"
#include "CSharpDialect.h"

#include "metallurgy/Implement.h"

#include "chordata/Utils.h"

void Dialect::CSharpDialect::Formulate(const Metallurgy::TypeDef &type) {
	//if (type.getShortName() != L"ConnectStream") return *this;
	const Metallurgy::Module &import = *type.getModule();

    std::wstring space = type.getName().getSpace();
    if (!space.empty()) {
	    *wout << GetIndent() << L"namespace " << type.getName().getSpace() << L" {" << std::endl;
	    UpIndent();
    }

	Metallurgy::Type *extends = type.getExtends();
	std::wstring extname;
    if (extends != NULL)
        extname = extends->getName().getFull();

	*wout << GetIndent();

	if (type.getVisibility() & Chordata::Flags::tdPublic)
		*wout << L"public ";

	if (type.getSemantics() == Chordata::Flags::tdInterface)
		*wout << L"interface ";
	else
		*wout << L"class ";

	*wout << type.getName().getShort();

	Metallurgy::TokenList tkImpls = type.getImplements();

	bool isExtended(false);
	if (extends = NULL) {
		if (extname.compare(L"System.Object")) {
			isExtended = true;
			*wout << L" : " << extname;
		}
	}

	for (size_t i(0); i < tkImpls.size(); ++i, isExtended = true)
		*wout << (isExtended ? L", " : L" : ") << dynamic_cast<Metallurgy::Implement *>(tkImpls[i])->getName().getFull();

	/*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 (i = 0; i < tkFields.size(); ++i)
		Formulate(*dynamic_cast<Metallurgy::Field *>(tkFields[i]));

	for (i = 0; i < tkProperties.size(); ++i) {
		Metallurgy::Property &property = *dynamic_cast<Metallurgy::Property *>(tkProperties[i]);
		Formulate(&property);

		tkMethods.remove(property.getGetter());
		tkMethods.remove(property.getSetter());
	}

	for (i = 0; i < tkMethods.size(); ++i)
		Formulate(dynamic_cast<Metallurgy::Method *>(tkMethods[i]));

	DownIndent();
	*wout << GetIndent() << L"}" << std::endl;

    if (!space.empty()) {
	    DownIndent();
	    *wout << L"}" << std::endl << std::endl;
    }
}

#if 0
    *wout << GetIndent() << L"namespace " << type.getName().getSpace() << L" {" << std::endl;

	UpIndent();

	Metallurgy::TokenList tkAttrs = type.getAttributes();
	for (uint32_t i(0); i < tkAttrs.size(); i++)
		Formulate(dynamic_cast<Metallurgy::Attribute *>(tkAttrs[i]));

	*wout << GetIndent();

	if (type.getVisibility() == Chordata::Flags::tdPublic)
		*wout << L"public ";

	if (type.getSemantics() == Chordata::Flags::tdInterface)
		*wout << L"interface ";
	else {
		std::wstring extends = type.getName().getFull();
	}
		
	else if (type.getSemantics() == Chordata::Flags::tdClass)
		*wout << L"class ";
	else if (type.isValueType())
		*wout << L"struct ";
	else {
		std::cerr << "Ummm... Magic?" << std::endl;
		exit(1);
	}

	*wout << type.getName().getShort();

	Metallurgy::TokenList tkImpls = type.getInterfaces();

	bool isExtended(false);
	if (RidFromToken(type.getExtends()) && type.getExtends() != 0x01000001 /* 16777217 = System.Object */) {
		isExtended = true;
		*wout << L" : " << import.getTypeName(type.getExtends());
	}

	for (Metallurgy::TokenList::iterator tkI = tkImpls.begin(); tkI != tkImpls.end(); tkI++, isExtended = true)
		*wout << (isExtended ? L", " : L" : ") <<  import.getTypeName(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(import.openField(*tkI));

	for (Metallurgy::TokenList::iterator tkI = tkProperties.begin(); tkI != tkProperties.end(); tkI++) {
		Metallurgy::MetaProperty &property(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(import.openMethod(*tkI));

	DownIndent();
	*wout << GetIndent() << L"}" << std::endl;

	DownIndent();
	*wout << L"}" << std::endl << std::endl;
#endif
