/* 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::Property *property) {
	//return;

	const Metallurgy::Method *method;
	if (property->getGetter() != NULL && property->getGetter()->getTokenType() == mdtMethodDef)
		method = property->getGetter();
	else if (property->getSetter() != NULL && property->getSetter()->getTokenType() == mdtMethodDef)
		method = property->getSetter();
	else return;

	*wout << /*XXX*/ L"\r\n" << GetIndent();

	const Metallurgy::ILMethodImpl *impl = dynamic_cast<const Metallurgy::ILMethodImpl *>(method->getImpl());

	const Metallurgy::TypeDef &type = *dynamic_cast<const Metallurgy::TypeDef *>(property->getType());

	if (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->IsStatic() || method->getName().getFull() == L".cctor")
			*wout << L"static ";
		else if (method->IsAbstract())
			*wout << L"abstract ";
	}

	const Metallurgy::Signature *signature = method->getSignature();

	if (signature->getReturn() == NULL)
		Formulate(signature->getElement(0));
	else
		Formulate(signature->getReturn());

	*wout << L" " << method->getName().getFull().substr(4) << L" {" << /*XXX*/ L"\r\n";

	UpIndent();

	if (property->getGetter() != NULL && property->getGetter()->getTokenType() == mdtMethodDef) {
		*wout << GetIndent() << L"get";

		const Metallurgy::Method *method = property->getGetter();
		if (type.getSemantics() != Chordata::Flags::tdInterface || method->IsAbstract())
			*wout << L";" << /*XXX*/ L"\r\n";
		else if (impl->getCodeRVA() == 0) {
			*wout << L" {" << /*XXX*/ L"\r\n";
			UpIndent();
			*wout << GetIndent() << L"// Native Method" << /*XXX*/ L"\r\n";
			DownIndent();
			*wout << GetIndent() << L"}" << /*XXX*/ L"\r\n";
		} else {
			ILEngineer::Blocks::Method *block = new ILEngineer::Blocks::Method(method);
			block->OptimizeGeneral();
			Formulate(block);
			delete block;
		}
	}

	if (property->getSetter() != NULL && property->getSetter()->getTokenType() == mdtMethodDef) {
		*wout << GetIndent() << L"set";

		const Metallurgy::Method *method = property->getSetter();
		if (type.getSemantics() != Chordata::Flags::tdInterface || method->IsAbstract())
			*wout << L";" << /*XXX*/ L"\r\n";
		else if (impl->getCodeRVA() == 0) {
			*wout << L" {" << /*XXX*/ L"\r\n";
			UpIndent();
			*wout << GetIndent() << L"// Native Method" << /*XXX*/ L"\r\n";
			DownIndent();
			*wout << GetIndent() << L"}" << /*XXX*/ L"\r\n";
		} else {
			ILEngineer::Blocks::Method *block = new ILEngineer::Blocks::Method(method);
			block->OptimizeGeneral();
			Formulate(block);
			delete block;
		}
	}

	DownIndent();

	*wout << GetIndent() << L"}" << /*XXX*/ L"\r\n";
}