/* 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 "ilengineer/Blocks/Method.h"

void Dialect::CSharpDialect::Formulate(Metallurgy::Method *method) {
	//if (method->getName() != L"ErrorDescription") return *this;
	*wout << /*XXX*/ L"\r\n";

	Metallurgy::TokenList tkAttrs = method->getAttributes();
	for (uint32_t i(0); i < tkAttrs.size(); i++)
		Formulate(dynamic_cast<Metallurgy::Attribute *>(tkAttrs[i]));

	*wout << GetIndent();

	const Metallurgy::ILMethodImpl *impl = dynamic_cast<const Metallurgy::ILMethodImpl *>(method->getImpl());

	const Metallurgy::TypeDef *type = dynamic_cast<const Metallurgy::TypeDef *>(method->getType());
	if (type == NULL || type->getSemantics() != Chordata::Flags::tdInterface) {
		switch (method->getAccess()) {
			case Chordata::Flags::mdPublic:
				*wout << L"public ";
			break;

			case Chordata::Flags::mdPrivate:
				*wout << L"private ";
			break;

			case Chordata::Flags::mdFamily:
				*wout << L"protected ";
			break;

			case Chordata::Flags::mdFamANDAssem:
				*wout << L"protected internal ";
			break;

			case Chordata::Flags::mdAssem:
				*wout << L"internal ";
			break;
		}

		if (method->IsVirtual())
			*wout << L"virtual ";

		if (!method->IsAbstract() && (impl == NULL || impl->getCodeRVA() == 0))
			*wout << L"extern ";

		if (method->IsStatic() || method->getName().getFull() == L".cctor")
			*wout << L"static ";
		else if (method->IsAbstract())
			*wout << L"abstract ";
	}

	const Metallurgy::Signature *signature = method->getSignature();

	if (method->getName().getFull() == L".ctor" || method->getName().getFull() == L".cctor")
		*wout << type->getName().getShort();
	else {
		if (signature->getReturn() != NULL) {
			Formulate(signature->getReturn());
			*wout << L" ";
		}
		*wout << method->getName().getFull();
	}

	*wout << L"(";

	bool notFirst(false);
	size_t seqParam(1);
	for (Metallurgy::ElementVector::const_iterator elI(signature->getElements().begin()); elI != signature->getElements().end(); elI++, seqParam++) {
		if (notFirst)
			*wout << L", ";
		notFirst = true;
		Formulate(*elI);
		const Metallurgy::Param *param = method->getParam(seqParam);
		if (param != NULL)
			*wout << L" " << param->getName().getFull();
	}

	/*TokenList tkParams(getParams());
	for (TokenList::iterator tkI(tkParams.begin()); tkI != tkParams.end(); tkI++) {
		MetaParam mdParam = m_Import->openParam(*tkI);
	}*/

	*wout << L")";

	if ((type != NULL && type->getSemantics() == Chordata::Flags::tdInterface) ||
		method->IsAbstract() ||
		(impl == NULL || impl->getCodeRVA() == 0))
	{
		*wout << L";" << /*XXX*/ L"\r\n";
	} else {
		ILEngineer::Blocks::Method *block = new ILEngineer::Blocks::Method(method);
		block->OptimizeGeneral();
		Formulate(dynamic_cast<ILEngineer::Statement *>(block));
		delete block;
	}
}