#include <assert.h>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <map>
using namespace std;

map<string,char> nucl2aa_mapping;

string complement(string seq)
{
  string result="";
  for(int i = 0 ; i < seq.length(); i++)
    {
      char c=seq[i];
      switch(c)
	{
	case 'A': result+="T"; break;
	case 'G': result+="C"; break;
	case 'C': result+="G"; break;
	case 'T': result+="A"; break;
	default: assert(0);
	}
    }
  return result;
}

string reverse(string seq)
{
  string result;
  for(int i=seq.length()-1; i>=0; i--)
    result+=seq[i];
  return result;
}

string nucl2aa(string seq)
{
  string result="";
  int l=seq.length();
  if (l%3!=0)
    l=3*(l/3);
  for(int i = 0 ; i < l; i+=3)
    {
      string codon=seq.substr(i,3);
      char aa=nucl2aa_mapping[codon];
      result+=aa;
    }
  return result;
}

void init_nucl2aa_table()
{
  nucl2aa_mapping["TTT"]='F';
  nucl2aa_mapping["TTC"]='F';
  nucl2aa_mapping["TTA"]='L';
  nucl2aa_mapping["TTG"]='L';
  nucl2aa_mapping["CTT"]='L';
  nucl2aa_mapping["CTC"]='L';
  nucl2aa_mapping["CTA"]='L';
  nucl2aa_mapping["CTG"]='L';
  nucl2aa_mapping["ATT"]='I';
  nucl2aa_mapping["ATC"]='I';
  nucl2aa_mapping["ATA"]='I';
  nucl2aa_mapping["ATG"]='M';
  nucl2aa_mapping["GTT"]='V';
  nucl2aa_mapping["GTC"]='V';
  nucl2aa_mapping["GTA"]='V';
  nucl2aa_mapping["GTG"]='V';
  nucl2aa_mapping["TCT"]='S';
  nucl2aa_mapping["TCC"]='S';
  nucl2aa_mapping["TCA"]='S';
  nucl2aa_mapping["TCG"]='S';
  nucl2aa_mapping["CCT"]='P';
  nucl2aa_mapping["CCC"]='P';
  nucl2aa_mapping["CCA"]='P';
  nucl2aa_mapping["CCG"]='P';
  nucl2aa_mapping["ACT"]='T';
  nucl2aa_mapping["ACC"]='T';
  nucl2aa_mapping["ACA"]='T';
  nucl2aa_mapping["ACG"]='T';
  nucl2aa_mapping["GCT"]='A';
  nucl2aa_mapping["GCC"]='A';
  nucl2aa_mapping["GCA"]='A';
  nucl2aa_mapping["GCG"]='A';
  nucl2aa_mapping["TAT"]='Y';
  nucl2aa_mapping["TAC"]='Y';
  nucl2aa_mapping["TAA"]='_';
  nucl2aa_mapping["TAG"]='_';
  nucl2aa_mapping["CAT"]='H';
  nucl2aa_mapping["CAC"]='H';
  nucl2aa_mapping["CAA"]='Q';
  nucl2aa_mapping["CAG"]='Q';
  nucl2aa_mapping["AAT"]='A';
  nucl2aa_mapping["AAC"]='A';
  nucl2aa_mapping["AAA"]='K';
  nucl2aa_mapping["AAG"]='K';
  nucl2aa_mapping["GAT"]='D';
  nucl2aa_mapping["GAC"]='D';
  nucl2aa_mapping["GAA"]='E';
  nucl2aa_mapping["GAG"]='E';
  nucl2aa_mapping["TGT"]='C';
  nucl2aa_mapping["TGC"]='C';
  nucl2aa_mapping["TGA"]='_';
  nucl2aa_mapping["TGG"]='W';
  nucl2aa_mapping["CGT"]='R';
  nucl2aa_mapping["CGC"]='R';
  nucl2aa_mapping["CGA"]='R';
  nucl2aa_mapping["CGG"]='R';
  nucl2aa_mapping["AGT"]='S';
  nucl2aa_mapping["AGC"]='S';
  nucl2aa_mapping["AGA"]='R';
  nucl2aa_mapping["AGG"]='R';
  nucl2aa_mapping["GGU"]='G';
  nucl2aa_mapping["GGC"]='G';
  nucl2aa_mapping["GGA"]='G';
  nucl2aa_mapping["GGG"]='G';
}

int main(int argc, char* argv[])
{
  init_nucl2aa_table();
  string seq="ACTGTCGTGCAGTCGCATGATGCATGCATGTGTGAATACGCGCGTGACGGTAGTGCAGTGCAGTGCAACACTAA";
  string rev=reverse(seq);
  string com=complement(seq);
  string rco=reverse(com);
  cout << seq << "\n";
  cout << rev << "\n";
  cout << com << "\n";
  cout << rco << "\n";
  string prot=nucl2aa(seq);
  cout << prot << "\n";

  map<string,string> checks;
  checks["std,0"]=seq;
  checks["std,1"]=seq.substr(1);
  checks["std,2"]=seq.substr(2);
  checks["rev,0"]=rev;
  checks["rev,1"]=rev.substr(1);
  checks["rev,2"]=rev.substr(2);
  checks["com,0"]=com;
  checks["com,1"]=com.substr(1);
  checks["com,2"]=com.substr(2);
  checks["rco,0"]=rco;
  checks["rco,1"]=rco.substr(1);
  checks["rco,2"]=rco.substr(2);
  
  // calculate the protein sequence for each
  int best_right_position=0;
  string whichone="";
  string usable="";
  for(map<string,string>::iterator it=checks.begin(); it!=checks.end(); it++)
    {
      string prot=nucl2aa(it->second);
      int pos=prot.find("_");
      if (pos>best_right_position)
	{
	  best_right_position=pos;
	  whichone=it->first;
	}
      else if (pos==best_right_position)
	{
	  whichone+="/"+it->first;
	}
      else
	{
	}	
      if (pos>0) usable+="/"+it->first;
      cout << it->first <<": " << nucl2aa(it->second) << "\n";
    }
  cout << "Longest sequence to stop codon " << whichone << "\n";
  cout << "Usable ones " << usable << "\n";
}

