/* Anakrino - .NET Reflection Browser
 * 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 "DocumentationViewer.h"

#include "resource.h"

namespace Anakrino {

	void Translate(std::wostringstream &html, DOM_Node data, const Metallurgy::Module *module, bool text = true) {
		for (DOM_Node child = data.getFirstChild(); child != NULL; child = child.getNextSibling()) {
			switch (child.getNodeType()) {
				case DOM_Node::ELEMENT_NODE: {
					if (child.getNodeName().equals(L"list")) {
						html << L"<table>";
						html << L"</table>";
					} else if (child.getNodeName().equals(L"para")) {
						html << L"<p>";
						Translate(html, child, module);
						html << L"</p>" << std::endl;
					} else if (child.getNodeName().equals(L"paramref")) {
						DOM_Node name = child.getAttributes().getNamedItem("name");
						html << L"<i>" << name.getNodeValue().rawBuffer() << L"</i>" << std::endl;
					} else if (child.getNodeName().equals(L"see")) {
						DOM_Node cref = child.getAttributes().getNamedItem("cref");
						if (cref == NULL)
							break;

						std::wstring key = cref.getNodeValue().rawBuffer();
						const Metallurgy::Token *token = module->XmlKeyLookup(key);
						const Metallurgy::IName *name = dynamic_cast<const Metallurgy::IName *>(token);

						html << L"<a href=\"tok://" << key << L"\">";
						if (name != NULL)
							html << name->getName().getShort();
						html << L"</a>";
					}
				} break;
				case DOM_Node::TEXT_NODE:
					if (!text) break;
					html << child.getNodeValue().rawBuffer();
				break;
			}
		}
	}

	void Riffle(std::wostringstream &html, DOM_Node node, wcstr_t name, const Metallurgy::Module *module) {
		if (node != NULL)
			for (DOM_Node child = node.getFirstChild(); child != NULL; child = child.getNextSibling())
				if (child.getNodeName().equals(name)) {
					Translate(html, child, module);
					return;
				}
	}

	std::wstring Suffix(const Metallurgy::TypeDef *type) {
		if (type->getSemantics() == Chordata::Flags::tdInterface)
			return L"Interface";

		Metallurgy::Type *extends = type->getExtends();
		if (extends != NULL) {
			std::wstring name = extends->getName();
			if (name == L"System.Enum")				return L"Enumeration";
			else if (name == L"System.ValueType")	return L"Structure";
		}

		return L"Class";
	}

	void DocumentationViewer::Select(const Metallurgy::Token *token) {
		Diapexis::Handle<Dialect::IDialect> dialect(binder->GetDialect(token));

		document2->clear();

		MSHTML::IHTMLElementPtr e_body = document2->body;
		MSHTML::IHTMLElement2Ptr e2_body = e_body;
		MSHTML::IHTMLBodyElementPtr body = e_body;

		DOM_Node node;
		binder->XmlDocument(token, node);

		std::wostringstream html;
		if (token != NULL)
			switch (token->getTokenType()) {
				case Chordata::Tokens::mdtFieldDef: {
					const Metallurgy::Field *mField = dynamic_cast<const Metallurgy::Field *>(token);
					const Metallurgy::Module *mModule = mField->getModule();

                    //  This isn't needed, this is really a safe operation.
					const Metallurgy::TypeDef *mTypeDef = dynamic_cast<const Metallurgy::TypeDef *>(mField->getType());
					std::wstring t_key = mTypeDef->getXmlMemberKey();
					std::wstring t_short = mTypeDef->getName().getShort();
					std::wstring t_space = mTypeDef->getName().getSpace();

					html << L"<h1>" << t_short << L"." << mField->getName().getFull() << L" Field</h1>" << std::endl;
					Riffle(html, node, L"summary", mModule);

					html << L"<pre>";
					html << L"</pre>" << std::endl << std::endl;

					html << L"<h4>Remarks</h4>" << std::endl;
					Riffle(html, node, L"remarks", mModule);

					html << L"<h4>Requirements</h4>" << std::endl;
					html << L"<p><b>Platforms: </b>Windows 98, Windows NT 4.0, Windows Millennium Edition, Windows 2000, Windows XP</p>" << std::endl;

					html << L"<h4>See Also</h4>" << std::endl;
					html << L"<p><a href=\"tok://" << t_key << L"\">" << t_short << L" " << Suffix(mTypeDef) << L"</a>";
					html << L" | <a href=\"tok://" << t_key << L"/members\">" << t_short << L" Members</a>";
					html << L" | <a href=\"tok://N:" << t_space << L"\">" << t_space << L" Namespace</a>";
					html << L"</p>" << std::endl;
				} break;

				case Chordata::Tokens::mdtMethodDef: {
					const Metallurgy::Method *mMethod = dynamic_cast<const Metallurgy::Method *>(token);
					const Metallurgy::Module *mModule = mMethod->getModule();

                    //  This isn't needed, this is really a safe operation.
                    const Metallurgy::TypeDef *mTypeDef = dynamic_cast<const Metallurgy::TypeDef *>(mMethod->getType());
					std::wstring t_key = mTypeDef->getXmlMemberKey();
					std::wstring t_short = mTypeDef->getName().getShort();
					std::wstring t_space = mTypeDef->getName().getSpace();

					html << L"<h1>" << t_short << L"." << mMethod->getName().getFull() << L" Method</h1>" << std::endl;
					Riffle(html, node, L"summary", mModule);

					html << L"<pre>";
					html << L"</pre>" << std::endl << std::endl;

					html << L"<h4>Parameters</h4>" << std::endl;
					html << L"<h4>Return Value</h4>" << std::endl;
					Riffle(html, node, L"returns", mModule);

					html << L"<h4>Exceptions</h4>" << std::endl;
					html << L"<h4>Remarks</h4>" << std::endl;
					Riffle(html, node, L"remarks", mModule);

					html << L"<h4>Requirements</h4>" << std::endl;
					html << L"<p><b>Platforms: </b>Windows 98, Windows NT 4.0, Windows Millennium Edition, Windows 2000, Windows XP</p>" << std::endl;

					html << L"<h4>See Also</h4>" << std::endl;
					html << L"<p><a href=\"tok://" << t_key << L"\">" << t_short << L" " << Suffix(mTypeDef) << L"</a>";
					html << L" | <a href=\"tok://" << t_key << L"/members\">" << t_short << L" Members</a>";
					html << L" | <a href=\"tok://N:" << t_space << L"\">" << t_space << L" Namespace</a>";
					html << L"</p>" << std::endl;
				} break;

				case Chordata::Tokens::mdtTypeDef: {
					const Metallurgy::TypeDef *mTypeDef = dynamic_cast<const Metallurgy::TypeDef *>(token);
					const Metallurgy::Module *mModule = mTypeDef->getModule();
					const Metallurgy::Assembly *mAssembly = mModule->getAssembly();

					std::wstring t_key = mTypeDef->getXmlMemberKey();
					std::wstring t_short = mTypeDef->getName().getShort();
					std::wstring t_space = mTypeDef->getName().getSpace();

					html << L"<h1>" << t_short << L" " << Suffix(mTypeDef) << L"</h1>" << std::endl;
					Riffle(html, node, L"summary", mModule);

					typedef std::stack<const Metallurgy::TypeDef *> TypeDefStack;
					TypeDefStack types;

					for (const Metallurgy::TypeDef *type = binder->Resolve(mTypeDef->getExtends()); type != NULL; type = binder->Resolve(type->getExtends()))
						types.push(type);

					html << L"<p>";
					for (uint32_t depth(1); !types.empty(); types.pop(), depth++) {
						const Metallurgy::TypeDef *type = types.top();
						html << L"<a href=\"tok://" << t_key << L"\">";
						html << type->getName().getShort() << L"</a><br />";
						for (uint32_t i(0); i < depth; i++)
							html << L"&nbsp;&nbsp;&nbsp;";
					}

					html << L"<b>" << t_short << L"</b>" << std::endl << std::endl;

					html << L"<pre>";
					html << L"</pre>" << std::endl << std::endl;

					html << L"<h4>Remarks</h4>" << std::endl;
					Riffle(html, node, L"remarks", mModule);

					html << L"<h4>Requirements</h4>" << std::endl;

					html << L"<p><b>Namespace: </b>" << t_space << L"</p>" << std::endl;
					html << L"<p><b>Platforms: </b>Windows 98, Windows NT 4.0, Windows Millennium Edition, Windows 2000, Windows XP</p>" << std::endl;
					html << L"<p><b>Assembly: </b>" << mAssembly->getName() << L" (in " << mAssembly->getShortPath() << L")</p>" << std::endl;

					html << L"<h4>See Also</h4>" << std::endl;
					html << L"<p><a href=\"tok://" << t_key << L"/members\">" << mTypeDef->getName().getShort() << L" Members</a>";
					html << L" | <a href=\"tok://N:" << t_space << L"\">" << t_space << L" Namespace</a>";
					html << L"</p>" << std::endl;
				} break;
			}

		e_body->innerHTML = html.str().c_str();
	}

}