#include <QtGui> 
#include "isoelectricpoint.h"
#include <cmath>
 
// if we include <QtGui> there is no need to include every class used: <QString>, <QFileDialog>,...
 
IEPapp::IEPapp(QWidget *parent)
{
    setupUi(this); // this sets up GUI

//		CENTER THE WINDOW
 QDesktopWidget *desktop = QApplication::desktop();
    
int screenWidth, width; 
int screenHeight, height;
int x, y;
QSize windowSize;
 
screenWidth = desktop->width(); // get width of screen
screenHeight = desktop->height(); // get height of screen
 
windowSize = size(); // size of our application window
width = windowSize.width(); 
height = windowSize.height();
 
// little computations
x = (screenWidth - width) / 2;
y = (screenHeight - height) / 2;
y -= 50;
 
// move window to desired coordinates
move ( x, y ); 
//		CENTER THE WINDOW END

    // signals/slots section
    connect( pushButtonBrowse, SIGNAL( clicked() ), this, SLOT( getPath() ) ); 
    connect( pushButtonAbout, SIGNAL( clicked() ), this, SLOT( about() ) ); 
    connect( pushButtonCalculate, SIGNAL( clicked() ), this, SLOT( calculate() ) ); 
    connect( pushButtonSave, SIGNAL( clicked() ), this, SLOT( save() ) ); 

textEdit->append( "paste here one, raw amino acid sequence of analysed protein (peptide) - uppercase leters counts only");

}
 
 
void IEPapp::getPath()
{
    QString path;
    
    path = QFileDialog::getOpenFileName(this, tr("Choose a file to open"),
        QString::null,
        tr("All Files (*.*)"));
 
    lineEdit->setText( path );
textEdit->clear();
QFile file(path);
 if (file.open(QIODevice::ReadOnly)) 
	{
         QString data(file.readAll());
	 textEdit->append(data);
	}
             //currentEditor->setPlainText(data);
}

 
 
void IEPapp::calculate()
{
QString protein;
protein = textEdit->toPlainText();
					//additional ProteinLenght value for reliability
int ProteinLength=0;			//lowercase letters and meaningless uppercase leters will be ignored

 	char Asp = 'D';
    	char Glu = 'E';
    	char Cys = 'C';
    	char Tyr = 'Y';
    	char His = 'H';
    	char Lys = 'K';
   	char Arg = 'R';

 	char Met = 'M';
	char Phe = 'F';
 	char Leu = 'L';
 	char Val = 'V';
 	char Ala = 'A';
 	char Gly = 'G';
 	char Gln = 'Q';
 	char Asn = 'N';
 	char Ile = 'I';
 	char Trp = 'W';
 	char Ser = 'S';
 	char Thr = 'T';
 	char Sec = 'U';
 	char Pro = 'P';

 int AspNumber = 0;	//D
 int GluNumber = 0;	//E
 int CysNumber = 0;	//C
 int TyrNumber = 0;	//Y
 int HisNumber = 0;	//H
 int LysNumber = 0;	//K
 int ArgNumber = 0;	//R

 //other uncharched aminoacids
 int MetNumber = 0; //M
 int PheNumber = 0; //F
 int LeuNumber = 0; //L
 int ValNumber = 0; //V
 int AlaNumber = 0; //A
 int GlyNumber = 0; //G
 int GlnNumber = 0; //Q
 int AsnNumber = 0; //N
 int IleNumber = 0; //I
 int TrpNumber = 0; //W
 int SerNumber = 0; //S
 int ThrNumber = 0; //T
 int SecNumber = 0; //U
 int ProNumber = 0; //P

double massAsp = 115.0886;	//D
double massGlu = 129.1155;	//E
double massCys = 103.1388;	//C
double massTyr = 163.1760;	//Y
double massHis = 137.1411;	//H
double massLys = 128.1741;	//K
double massArg = 156.1875;	//R
//other uncharched aminoacids
double massMet = 131.1926;	//M
double massPhe = 147.1766;	//F
double massLeu = 113.1594;	//L
double massVal = 99.1326;	//V
double massAla = 71.0788;	//A
double massGly = 57.0519;	//G
double massGln = 128.1307;	//Q
double massAsn = 114.1038;	//N
double massIle = 113.1594;	//I
double massTrp = 186.2132;	//W
double massSer = 87.0782;	//S
double massPro = 97.1167;	//P
double massThr = 101.1051;	//T
double massSec = 141.05;	//U
double mass = 18.01524;	//H2O


double pKCterm, pKAsp, pKGlu, pKCys, pKTyr, pKHis, pKNterm, pKLys, pKArg;

		QString combo;
		combo = comboBox->currentText();

		textEdit->append( " " );
		if (combo == "EMBOSS")
		{
			textEdit->append( "pK values according <b>EMBOSS</b> were used" );
			pKCterm=3.6;
			pKAsp=3.9;
			pKGlu=4.1;
			pKCys=8.5;
			pKTyr=10.1;
			pKHis=6.5;
			pKNterm=8.6;
			pKLys=10.8;
			pKArg=12.5;
		}

		if (combo == "DTASelect")
		{
			textEdit->append( "pK values according <b>DTASelect</b> were used" );
			pKCterm=3.1;
			pKAsp=4.4;
			pKGlu=4.4;
			pKCys=8.5;
			pKTyr=10.0;
			pKHis=6.5;
			pKNterm=8.0;
			pKLys=10.0;
			pKArg=12.0;
		}

		if (combo == "Solomon")
		{
			textEdit->append( "pK values according <b>Solomon</b> were used" );
			pKCterm=2.4;
			pKAsp=3.9;
			pKGlu=4.3;
			pKCys=8.3;
			pKTyr=10.1;
			pKHis=6.0;
			pKNterm=9.6;
			pKLys=10.5;
			pKArg=12.5;
		}

		if (combo == "Sillero")
		{
			textEdit->append( "pK values according <b>Sillero</b> were used" );
			pKCterm=3.2;
			pKAsp=4.0;
			pKGlu=4.5;
			pKCys=9.0;
			pKTyr=10.0;
			pKHis=6.4;
			pKNterm=8.2;
			pKLys=10.4;
			pKArg=12.0;
		}

		if (combo == "Rodwell")
		{
			textEdit->append( "pK values according <b>Rodwell</b> were used" );
			pKCterm=3.1;
			pKAsp=3.68;
			pKGlu=4.25;
			pKCys=8.33;
			pKTyr=10.07;
			pKHis=6.0;
			pKNterm=8.0;
			pKLys=11.5;
			pKArg=11.5;
		}

		if (combo == "Patrickios")
		{
			textEdit->append( "pK values according <b>Patrickios</b> were used\n" );
			textEdit->append( "Watch out, this model is highly simplified" );
			pKCterm=4.2;
			pKAsp=4.2;
			pKGlu=4.2;
			pKCys=0.0;
			pKTyr=0.0;
			pKHis=0.0;
			pKNterm=11.2;
			pKLys=11.2;
			pKArg=11.2;
		}

		if (combo == "Wikipedia")
		{
			textEdit->append( "pK values according <b>Wikipedia</b> were used\n" );
			pKCterm=3.65;
			pKAsp=3.9;
			pKGlu=4.07;
			pKCys=8.18;
			pKTyr=10.46;
			pKHis=6.04;
			pKNterm=8.2;
			pKLys=10.54;
			pKArg=12.48;
		}


	for (int i = 0; i <= protein.length() - 1; ++i)              //  we are looking for charged amino acids
     {
               if (protein[i] == Asp)
		{
                  ++AspNumber;
		  mass += massAsp;
		  ++ProteinLength;
 		}

               if (protein[i] == Glu)
		{
                  ++GluNumber;
		  mass += massGlu;
		  ++ProteinLength;
 		}
 
               if (protein[i] == Cys)
		{
                  ++CysNumber;
		  mass += massCys;
		  ++ProteinLength;
 		}
 
               if (protein[i] == Tyr)
		{
                  ++TyrNumber;
		  mass += massTyr;
		  ++ProteinLength;
 		}
 
               if (protein[i] == His)
		{
                  ++HisNumber;
		  mass += massHis;
		  ++ProteinLength;
 		}
 
               if (protein[i] == Lys)
		{
                  ++LysNumber;
		  mass += massLys;
		  ++ProteinLength;
 		}
 
               if (protein[i] == Arg)
		{
                  ++ArgNumber;
		  mass += massArg;
		  ++ProteinLength;
 		}

               if (protein[i] == Met)
		{
                  ++MetNumber;
		  mass += massMet;
		  ++ProteinLength;
 		}

               if (protein[i] == Phe)
		{
                  ++PheNumber;
		  mass += massPhe;
		  ++ProteinLength;
 		}

               if (protein[i] == Leu)
		{
                  ++LeuNumber;
		  mass += massLeu;
		  ++ProteinLength;
 		}

               if (protein[i] == Val)
		{
                  ++ValNumber;
		  mass += massVal;
		  ++ProteinLength;
 		}

               if (protein[i] == Ala)
		{
                  ++AlaNumber;
		  mass += massAla;
		  ++ProteinLength;
 		}

               if (protein[i] == Gly)
		{
                  ++GlyNumber;
		  mass += massGly;
		  ++ProteinLength;
 		}

               if (protein[i] == Gln)
		{
                  ++GlnNumber;
		  mass += massGln;
		  ++ProteinLength;
 		}

               if (protein[i] == Asn)
		{
                  ++AsnNumber;
		  mass += massAsn;
		  ++ProteinLength;
 		}

               if (protein[i] == Ile)
		{
                  ++IleNumber;
		  mass += massIle;
		  ++ProteinLength;
 		}

               if (protein[i] == Trp)
		{
                  ++TrpNumber;
		  mass += massTrp;
		  ++ProteinLength;
 		}

               if (protein[i] == Ser)
		{
                  ++SerNumber;
		  mass += massSer;
		  ++ProteinLength;
 		}

               if (protein[i] == Thr)
		{
                  ++ThrNumber;
		  mass += massThr;
		  ++ProteinLength;
 		}

               if (protein[i] == Sec)
		{
                  ++SecNumber;
		  mass += massSec;
		  ++ProteinLength;
 		}

               if (protein[i] == Pro)
		{
                  ++ProNumber;
		  mass += massPro;
		  ++ProteinLength;
 		}
     }

     double NQ = 0.0; //net chare in given pH

     double QN1=0;  //C-terminal charge
     double QN2=0;  //D charge
     double QN3=0;  //E charge
     double QN4=0;  //C charge
     double QN5=0;  //Y charge
     double QP1=0;  //H charge
     double QP2=0;  //NH2 charge
     double QP3=0;  //K charge
     double QP4=0;  //R charge

     double pH = 6.5;             //starting point pI = 6.5 - theoretically it should be 7, but
                                  //average protein pI is 6.5 so we increase the probability
     double pHprev = 0.0;         //of finding the solution
     double pHnext = 14.0;        //0-14 is possible pH range

     double E = 0.01;             //epsilon means precision [pI = pH ? E]
     double temp = 0.0;
 
for(;;)                //the infinite loop
 {
     QN1=-1/(1+pow(10,(pKCterm-pH)));                                        
     QN2=-AspNumber/(1+pow(10,(pKAsp-pH)));           
     QN3=-GluNumber/(1+pow(10,(pKGlu-pH)));           
     QN4=-CysNumber/(1+pow(10,(pKCys-pH)));           
     QN5=-TyrNumber/(1+pow(10,(pKTyr-pH)));        
     QP1=HisNumber/(1+pow(10,(pH-pKHis)));            
     QP2=1/(1+pow(10,(pH-pKNterm)));                
     QP3=LysNumber/(1+pow(10,(pH-pKLys)));           
     QP4=ArgNumber/(1+pow(10,(pH-pKArg)));            
 
     NQ=QN1+QN2+QN3+QN4+QN5+QP1+QP2+QP3+QP4;

//%%%%%%%%%%%%%%%%%%%%%%%%%   BISECTION   %%%%%%%%%%%%%%%%%%%%%%%%
 
     if(NQ<0)              //we are out of range, thus the new pH value must be smaller    
      {                   
         temp = pH;
         pH = pH-((pH-pHprev)/2);
         pHnext = temp;
         //cout<<"pH: "<<pH<<", \tpHnext: "<<pHnext<<endl;
     }
     else                  //we used to small pH value, so we have to increase it
     {                     
         temp = pH;
         pH = pH + ((pHnext-pH)/2);
         pHprev = temp;
         //cout<<"pH: "<<pH<<",\tpHprev: "<<pHprev<<endl;
  
     }
 
        if ((pH-pHprev<E)&&(pHnext-pH<E)) //terminal condition, finding pI with given precision
           break;
    
 //conclusions: due the usage of bisection we could shorten the calculation to 10-12 iterations!!!
 
  }

   // textEdit->append( "Path to file: " + lineEdit->text() );
 if ( ProteinLength == 0)
	textEdit->append( "<h2><font color=red>\nIt looks like you forget to load sequence or it is inappropriate</font></h2>");
else
{
    textEdit->append( "Analysed protein (peptide) has " + QString::number(ProteinLength) + " amino acids");
    textEdit->append( "Protein mass: " + QString::number(mass) + " Da\n");
    textEdit->append( "<h3><font color=navy>Isoelectric point: " + QString::number(pH) + "</font></h3>\n" );
}

}
 

void IEPapp::about() 
{
    QMessageBox::about(this,"About Isoelectric point",
                "\n\nIsoelectric Point Calculator version 1.0\n\n"
		"Project site: http://isoelectric.ovh.org"
		"\n\nLukasz Kozlowski, 2007"
		"\n\nAny sugestions and comments"
                "\nplease send to: lukaskoz@o2.pl");
}


void IEPapp::save() 
{
	
     QString fileName = QFileDialog::getSaveFileName(this,
                         tr("Choose a file name"), ".",
                         tr("Text Files (*.txt *.text)"));
     if (fileName.isEmpty())
         return;
     QFile file(fileName);
     if (!file.open(QFile::WriteOnly | QFile::Text)) {
         QMessageBox::warning(this, tr("Dock Widgets"),
                              tr("Cannot write file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
         return;
     }

     QTextStream out(&file);
     QApplication::setOverrideCursor(Qt::WaitCursor);
     out << textEdit->toPlainText();
     QApplication::restoreOverrideCursor();

}
