/* 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 "resource.h"
#include "TachyonViewer.h"

#include "theoretic/Optimals.h"

#ifdef TACHYON_JAVA
void ThisSucks(JNIEnv *env, jthrowable evil) {
	jclass c_java_lang_Object = env->FindClass("java/lang/Object");
	jmethodID m_java_lang_Object_toString = env->GetMethodID(c_java_lang_Object, "toString", "()Ljava/lang/String;");

	jstring name = (jstring) env->CallObjectMethod(evil, m_java_lang_Object_toString);

	jclass c_java_io_StringWriter = env->FindClass("java/io/StringWriter");
	jobject sw = env->NewObject(c_java_io_StringWriter, env->GetMethodID(c_java_io_StringWriter, "<init>", "()V"));

	jclass c_java_io_PrintWriter = env->FindClass("java/io/PrintWriter");
	jobject pw = env->NewObject(c_java_io_PrintWriter, env->GetMethodID(c_java_io_PrintWriter, "<init>", "(Ljava/io/Writer;)V"), sw);

	jclass c_java_lang_Throwable = env->FindClass("java/lang/Throwable");
	jmethodID m_java_lang_Throwable_printStackTrace = env->GetMethodID(c_java_lang_Throwable, "printStackTrace", "(Ljava/io/PrintWriter;)V");
	env->CallVoidMethod(evil, m_java_lang_Throwable_printStackTrace, pw);

	jstring trace = (jstring) env->CallObjectMethod(sw, m_java_lang_Object_toString, pw);
	jstring value = (jstring) env->CallObjectMethod(evil, m_java_lang_Object_toString, pw);

	::MessageBoxA(NULL, env->GetStringUTFChars(trace, NULL), env->GetStringUTFChars(value, NULL), MB_OK);
	exit(0);
}
#endif

namespace Anakrino {

	void TachyonViewer::Select(const Metallurgy::Token *token) {
		SetWindowText(L"");

		if (token == NULL || token->getTokenType() != Chordata::Tokens::mdtMethodDef)
			return;

		const Metallurgy::ILMethodImpl *impl = dynamic_cast<const Metallurgy::ILMethodImpl *>(dynamic_cast<const Metallurgy::Method *>(token)->getImpl());
        if (impl == NULL)
            return;

		uint8_t *data = impl->getOffset();
		uint32_t length(impl->getLength());

#ifdef TACHYON_JAVA
		jthrowable evil;
		if ((evil = env->ExceptionOccurred()) != 0) {
			env->ExceptionDescribe();
			env->ExceptionClear();

			ThisSucks(env, evil);
		}

		jbyteArray bytes = env->NewByteArray(length);
		env->SetByteArrayRegion(bytes, 0, length, (signed char *) data);
		jobject value = env->CallObjectMethod(engine, m_org_ninetjer_ilel_parse, bytes);

		if ((evil = env->ExceptionOccurred()) != 0) {
			env->ExceptionDescribe();
			env->ExceptionClear();

			ThisSucks(env, evil);
		}

		//::SetWindowTextA(m_hWnd, env->GetStringUTFChars((jstring) value, NULL));
#else 
		std::wostringstream buffer;
        Theoretic::OpGraph *graph = engine->Parse(impl->getData());

#if 0
        using namespace Theoretic::Optimals;
        widenOptimal(*graph);
#else
        typedef std::pair<Theoretic::Operation *, uint32_t> RedozPair;
        typedef std::map<Theoretic::Operation *, uint32_t> RedozMap;

        RedozMap redoz;

        buffer << L"'(";

        uint32_t current(0);
        const Theoretic::OperSet &rops = graph->GetOps();
        for (Theoretic::OperSet::const_iterator rop = rops.begin(); rop != rops.end(); ++rop)
            redoz.insert(RedozPair(*rop, ++current));

        for (RedozMap::const_iterator doz = redoz.begin(); doz != redoz.end(); ++doz) {
            buffer << L"(register " << doz->second << L" #S(VERTEX :EDGES (";
            const Theoretic::Operation::LinkMap &links = doz->first->GetLinks();
            for (Theoretic::Operation::LinkMap::const_iterator link = links.begin(); link != links.end(); ++link) 
                buffer << L"#S(EDGE :VERTEX " << redoz[link->second[0]] << L" :VISITED NIL) ";
            buffer << L") :VISITED NIL))\r\n";
        }

        buffer << L")  Root: " << redoz[graph->GetRoot()] << L"\r\n";
#endif

        const Theoretic::OperSet &ops = graph->GetOps();
        for (Theoretic::OperSet::const_iterator op = ops.begin(); op != ops.end(); ++op)
            buffer << **op;

        delete graph;
		SetWindowText(buffer.str().c_str());
#endif

	}

}