#include "Aminoacid_name.h"

#include "Array.h"
#include "DbC.h"

#include "Log.h"
//#include <string.h>
//#include <stdio.h>

namespace MM
{
    const Text Aminoacid_name::wrong("?");

namespace
{

class Aminoacid_name_impl : protected DbC
{
    struct Row
    {
        Text one_;
        Text three_;
        Text full_;

        Row (const Text & one, const Text & three, const Text & full) 
            : one_(one), three_(three), full_(full) { }
    };

    Array <Row>    table_;

    Aminoacid_name_impl()
    {
        table_.push_back (Row ("A", "Ala", "Alanine"));
        table_.push_back (Row ("R", "Arg", "Arginine"));
        table_.push_back (Row ("N", "Asn", "Asparagine"));
        table_.push_back (Row ("D", "Asp", "Aspartic acid"));
        table_.push_back (Row ("C", "Cys", "Cysteine"));
        table_.push_back (Row ("E", "Glu", "Glutamic acid"));
        table_.push_back (Row ("Q", "Gln", "Glutamine"));
        table_.push_back (Row ("G", "Gly", "Glycine"));
        table_.push_back (Row ("H", "His", "Histidine"));
        table_.push_back (Row ("I", "Ile", "Isoleucine"));
        table_.push_back (Row ("L", "Leu", "Leucine"));
        table_.push_back (Row ("K", "Lys", "Lysine"));
        table_.push_back (Row ("M", "Met", "Methionine"));
        table_.push_back (Row ("F", "Phe", "Phenylalanine"));
        table_.push_back (Row ("P", "Pro", "Proline"));
        table_.push_back (Row ("S", "Ser", "Serine"));
        table_.push_back (Row ("T", "Thr", "Threonine"));
        table_.push_back (Row ("W", "Trp", "Tryptophan"));
        table_.push_back (Row ("Y", "Tyr", "Tyrosine"));
        table_.push_back (Row ("V", "Val", "Valine"));

        ENSURE ("20 aminoacids", table_.size() == 20);
    }

public:
    static Aminoacid_name_impl & singleton()
    {
        static Aminoacid_name_impl instance; 
        return instance;
    }

    const Text &    handle_one_letter   (const Text &name)
    {
        const Text arg = name.to_upper();
    
        if (name.length() == 1)
        {
            for (int i=0;  i<table_.size();  ++i)
            {
//                if (stricmp (table_[i].one_.c_str(), name.c_str()) == 0)
                Text current_name = table_[i].one_;
                if (current_name.to_upper() == arg)
                    return table_[i].one_;
            }
            return Aminoacid_name::wrong;
        }
        else if (name.length() == 3)
        {
            for (int i=0;  i<table_.size();  ++i)
            {
//                if (stricmp (table_[i].three_.c_str(), name.c_str()) == 0)
                Text current_name = table_[i].three_;
                if (current_name.to_upper() == arg)
                    return table_[i].one_;
           }
                return Aminoacid_name::wrong;
        }
        else
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].full_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].full_;
                if (current_name.to_upper() == arg)
                    return table_[i].one_;
            }
            return Aminoacid_name::wrong;
        }
    }

    const Text &    handle_three_letter (const Text &name)
    {
        const Text arg = name.to_upper();

        if (name.length() == 1)
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].one_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].one_;
                if (current_name.to_upper() == arg)
                    return table_[i].three_;
            }
            return Aminoacid_name::wrong;
        }
        else if (name.length() == 3)
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].three_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].three_;
                if (current_name.to_upper() == arg)
                    return table_[i].three_;
            }
                return Aminoacid_name::wrong;
        }
        else
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].full_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].full_;
                if (current_name.to_upper() == arg)
                    return table_[i].three_;
            }
            return Aminoacid_name::wrong;
        }
    }

    const Text &    handle_full         (const Text &name)
    {
        const Text arg = name.to_upper();

        if (name.length() == 1)
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].one_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].one_;
                if (current_name.to_upper() == arg)
                    return table_[i].full_;
            }
            return Aminoacid_name::wrong;
        }
        else if (name.length() == 3)
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].three_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].three_;
                if (current_name.to_upper() == arg)
                    return table_[i].full_;
            }
            return Aminoacid_name::wrong;
        }
        else
        {
            for (int i=0;  i<table_.size();  ++i)
//                if (stricmp (table_[i].full_.c_str(), name.c_str()) == 0)
            {
                Text current_name = table_[i].full_;
                if (current_name.to_upper() == arg)
                    return table_[i].full_;
            }
            return Aminoacid_name::wrong;
        }
    }

    Aminoacid_name *link;
};

}//namespace

const Text & Aminoacid_name::
one_letter (const Text &name)
{
    return Aminoacid_name_impl::singleton ().handle_one_letter (name);
}

const Text & Aminoacid_name::
three_letter (const Text &name)
{
    return Aminoacid_name_impl::singleton ().handle_three_letter (name);
}

const Text & Aminoacid_name::
full (const Text &name)
{
    return Aminoacid_name_impl::singleton ().handle_full (name);
}

bool Aminoacid_name::
is_valid (const Text &name)
{
    return Aminoacid_name::one_letter (name) != Aminoacid_name::wrong;
}

}//MM
