#ifdef WIN32
#pragma warning(disable : 4786)
#pragma warning(disable : 4503)
#endif

#include "Fine_type_impl.h"

#include "Table_from_file.h"
#include "Path.h"
#include "Flaw.h"
#include "User.h"

namespace MM
{
using namespace std;

Fine_type_impl::
Fine_type_impl ()
:
    counter_(0)
{
    id_to_name_[Fine_type::none] = "-";
    name_to_id_["-"]             = Fine_type::none;
    ++counter_;
}

Fine_type_impl & Fine_type_impl::
singleton ()
{
    static Fine_type_impl instance;
    return instance;
}

/*Fine_type::
Fine_type ()
{
    counter_ = 0;
//    Line_impl *column_types = new Line_impl;
//    column_types->add (std::string());

//    Table_from_file table
//        (Text(DIR_force_field) + "Fine_types.txt", column_types);

}
//*/

bool Fine_type_impl::
handle_exist (char const* name)
{
    std::map <std::string, int>::iterator result = name_to_id_.find (name);
    if (result == name_to_id_.end())
        return false;
    return true;
}

int Fine_type_impl::
handle_id (char const* name)
{
    std::map <std::string, int>::iterator result = name_to_id_.find (name);
    if (result == name_to_id_.end())
        FLAW (Text("No Fine_type - ") + name);
        //return Fine_type::none;

    return result->second;
}

char const* Fine_type_impl::
handle_name (int id)
{
    std::map <int, std::string>::iterator result = id_to_name_.find (id);
    if (result == id_to_name_.end())
        FLAW (Text("No Fine_type - ") + id);
    return result->second.c_str();
}


char const* Fine_type_impl::
handle_to (char const * fine_type, char const * in, double * charge)
{
    std::map <std::string, std::map <std::string, std::pair<std::string, double> > >::iterator
        fine_it = mm_map_.find (fine_type);

    if (fine_it == mm_map_.end())
        FLAW (Text("No Fine_type - ") + fine_type);

    std::map <std::string, std::pair<std::string, double> >::iterator
        in_it = fine_it->second.find (in);

    if (in_it == fine_it->second.end())
        return 0;

    if (charge != 0)
    {
        double new_charge = in_it->second.second;
        if (new_charge != no_charge)
            *charge = new_charge;
    }

    //return in_it->second.c_str();
    return in_it->second.first.c_str();
}

void Fine_type_impl::
handle_map (char const * fine_type, char const * mm_type, double charge,
            char const * in)
{
    char const * result = handle_to (fine_type, in, 0);
    
    if (result != 0)
    {
        if (std::string (result) != mm_type)
            to_user().warning (Text("Can not map '") + fine_type +
            "' to '" + mm_type + "'.\nFine_type '" + fine_type +
            "' already was mapped to '" + in + "' as '" + result + "'.");
        return;
    }

//    mm_map_[fine_type][in] = mm_type;
    mm_map_[fine_type][in] = pair<string, double>(mm_type, charge);

    string ff (in);
    if (ff != "PDB" && ff != "SYBYL" && ff != "Name")
        ff_set_.insert (ff);
}

void Fine_type_impl::
handle_force_field_list (Array <Text> & list)
{
    for (std::set <std::string>::iterator it = ff_set_.begin ();
         it != ff_set_.end();  ++it)
    {
        list.push_back (it->c_str());
//        result += it->c_str();
//        result += "\n";
    }
}

void Fine_type_impl::
handle_add (char const* name)
{
    if (name_to_id_.find (name) != name_to_id_.end())
        FLAW (Text("Fine_type '") + name + "' already exist.");

    id_to_name_[counter_] = name;
    name_to_id_[name]     = counter_;
    //mm_map_    [name]     = std::map <std::string, std::string> ();
    mm_map_    [name]     = 
        std::map <std::string, std::pair<std::string, double> > ();
    ++counter_;
}
/*
void Fine_type_impl::
handle_erase (int id)
{
    std::map <int, std::string>::iterator result = id_to_name_.find (id);
    if (result == id_to_name_.end())
        FLAW (Text("No Fine_type - ") + id);
    name_to_id_.erase (result->second);
    id_to_name_.erase (id);
}

void Fine_type_impl::
handle_erase (char const* name)
{
    std::map <std::string, int>::iterator result = name_to_id_.find (name);
    if (result == name_to_id_.end())
        FLAW (Text("No Fine_type - ") + name);
    id_to_name_.erase (result->second);
    name_to_id_.erase (name);
}//*/

}//MM
