/* Exemplar - Command Line Interface to ILEngineer
 * 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 "menes/options.hpp"
#include "menes/win32/charset.hpp"

#pragma warning ( disable : 4503 )

std::wstring Widen(const char *data) {
    size_t length(strlen(data) + 2);
    wchar_t *buff = new wchar_t[length];
    _snwprintf(buff, length, L"%S", data);
    std::wstring wide = buff;
    delete [] buff;
    return wide;
}

void usage() {
}

int main(int argc, char *argv[]) {
    ManualOverride.SetName("Anakrino");
    Diapexis::PexInitialize();

    bool verbose;
    bool theoretic;

    typedef std::set<std::string> type_set;
    type_set types;

    menes::options options;

    options.flag('v', verbose);
    options.flag('t', theoretic);

    options.pool('c', types);

    options.parse(argc - 1, argv + 1, usage);

    const menes::options::free_set &frees = options.free();

    for (menes::options::free_set::const_iterator free = frees.begin(); free != frees.end(); ++free) {
        Diapexis::Handle<Dialect::IDialect> dialect(L"Dialect.CSharpDialect");
        dialect->Assign(std::wcout);

        Metallurgy::Module module(Widen(free->c_str()));
        Metallurgy::TokenList tokens;

        if (types.size() == 0)
            tokens = module.getTypeDefs();
        else for (type_set::iterator type = types.begin(); type != types.end(); ++type) {
            Metallurgy::TypeDef *def = module.FindTypeDef(Widen(type->c_str()));
            if (def == NULL) {
                std::cerr << *type << " not found" << std::endl;
                exit(-1);
            }
            tokens.insert(def);
        }

        /*if (theoretic) {
            Theoretic::IEngine *engine;
            engine = Theoretic::IEngine::GetInstance(L"msil");

            for (int i(0); i < tokens.size(); ++i) {
                Metallurgy::TypeDef *type = dynamic_cast<Metallurgy::TypeDef *>(tokens[i]);
                Metallurgy::TokenList mtds = type->getMethods();
                for (int j(0); j < mtds.size(); ++j) {
                    std::wcout << L"===================" << std::endl;
                    const Metallurgy::Method *mMethod = dynamic_cast<const Metallurgy::Method *>(mtds[j]);
                    const Metallurgy::Module *mModule = mMethod->getModule();

                    const Metallurgy::ILMethodImpl *impl = dynamic_cast<const Metallurgy::ILMethodImpl *>(mMethod->getImpl());
                    if (impl == NULL)
                        break;

                    Theoretic::OpGraph *graph = engine->Parse(impl->getData());
                    graph->Cement(*mMethod);

                    const Theoretic::OperSet &ops = graph->GetOps();
                    for (Theoretic::OperSet::const_iterator op = ops.begin(); op != ops.end(); ++op)
                        std::wcout << **op;

                    std::wcout << L"-------------------" << std::endl;
                    Theoretic::Optimals::widenOptimal(*graph);
                    for (op = ops.begin(); op != ops.end(); ++op)
                        std::wcout << **op;

                    std::wcout << L"-------------------" << std::endl;
                    graph->Optimize();

                    for (op = ops.begin(); op != ops.end(); ++op)
                        std::wcout << **op;
                    std::wcout << L"===================" << std::endl << std::endl;
                }
            }
        } else*/ for (int i(0); i < tokens.size(); ++i)
            dialect->Formulate(*dynamic_cast<Metallurgy::TypeDef *>(tokens[i]));
    }

    Diapexis::PexTerminate();
    return 0;
}