import java.io.*;
import java.util.*;
import Text;

class Reaction
{
  //======================================================//
  // Dr. Turhan Coban                                     //
  // TUBITAK Marmara Research Center                      //
  // Energy Systems and Environmental Research Institute  //
  // Phone : 90 (262) 641 2300-3917                       //
  // email : turhan@mam.gov.tr                            //
  //======================================================//
  // Class Description :
  //------------------------------------------------------
  // This program calculates energy, adiabatic flame temperature
  // entropy and gibbs free energy for a given reaction
  // Basic reaction data is given in the file called Reaction.dat
  // Format of the data :
  // reactionname
  // number_of_the_chemicals
  // gas_name reactant_mole prodoct_mole
  // .......
  // gas_name reactant_mole prodoct_mole
  //-----------------
  // sample data :
  //-----------------
  // c2h6combustion
  // 5
  // c2h6 1 0
  // o2 3 0
  // n2 11.28 11.28
  // co2 0 2
  // h2o 0 2
  //------------------
  // the available gas_name's can be checked from data file
  // Gas.dat
  // Variable Identification
  //-----------------------------------------------------
  // ngas     : number of gases in reaction (integer variable)
  // reacname : reaction name  (String variable)
  // gasR,gasP: gas objects for reactants and products
  //            (array objects of class Gas)
  //            see Gas.java for details
  // natom    : number of atoms in the reaction
  // nr,np    : number of Moles of reactants and products
  //            (double vector array)
  // nrt,npt  : total number of moles for reactants and products
  // reacFile : reaction file channel variable (Class File)
  // atomList : list of the atoms in the reaction
  public int ngas;
  String reacName;
  Gas gasR[],gasP[];
  public int natom;
  Atom atomList[];
  File reacFile;
  double nr[],np[];
  double nrt,npt;

  public Reaction(String name) throws IOException
  {
  reacFile=new File("Reaction.dat");
  reacFile=new File(reacFile.getAbsolutePath());
  try
     {
     DataInputStream cfin=new DataInputStream(new FileInputStream(reacFile));
     int ierror=1;
     natom=0;
     try
       {
       while(cfin!=null)
         {
         reacName=Text.readString(cfin);
         if(reacName.equals(name)) {ierror=0;break;}
         }
       }
       catch(EOFException e_eof)
         {
         System.out.println("error required gas mixture "+name+" is not found");
         cfin.close();return;
         }
       ngas=Text.readInt(cfin);
       gasR=new Gas[ngas];
       gasP=new Gas[ngas];
       nr=new double[ngas];
       np=new double[ngas];
       nrt=0;
       npt=0;
       String tempGasName;
       Double n1,n2;
       for(int i=0;i<ngas;i++)
         {
         tempGasName=Text.readString(cfin);
         nr[i]=Text.readDouble(cfin);
         np[i]=Text.readDouble(cfin);
         nrt+=nr[i];
         npt+=np[i];
         gasR[i]=new Gas(tempGasName,nr[i]);
         gasP[i]=new Gas(tempGasName,np[i]);
         }
       }
     catch(FileNotFoundException fnfe) {System.out.println("File Not Found");}
     arrange_atoms();
     }   //end of constructor

     public void arrange_atoms() throws IOException
     {
     // atomic structure of the reactants
     int i,j;
        for(i=0;i<ngas;i++)
        {
             for(j=0;j<gasR[i].natom;j++)
	     {
             add_atom(i,j);
             }
        }
     }

     public int  add_atom(int i,int j) throws IOException
     {
     //determine and order the atomic structure
     int k;
       for(k=0;k<natom;k++)
       {
       if(gasR[i].atomList[j].symbol.equals(atomList[k].symbol))
         {
         atomList[k]=new Atom(atomList[k].symbol,atomList[k].N+gasR[i].atomList[j].N*gasR[i].N);
         return 1;
         }
       }
     Atom atomL[];
     atomL=new Atom[natom+1];
     for(k=0;k<natom;k++)
       atomL[k]=new Atom(atomList[k]);
     atomL[natom]=new Atom(gasR[i].atomList[j].symbol,gasR[i].atomList[j].N*gasR[i].N);
     atomList=atomL;
     natom+=1;
     return 2;
     }

     public String toString()
     {
       // writes chemical reaction in chemistry norm
       String s="";
       for(int i=0;i<ngas;i++)
       {
       if(nr[i]==1)
           { s+=gasR[i].toString(); }
       else if(nr[i]!=0)
           { s+=nr[i]+" "+gasR[i].toString(); }
       if(i!=(ngas-1) && nr[i]!=0 ) s+=" + ";
       }
       if(s.endsWith(" + "))
         s=s.substring(0,s.length()-3);
       s+=" --> ";
       for(int i=0;i<ngas;i++)
       {
       if(np[i]==1)
           { s+=gasP[i].toString(); }
       else if(np[i]!=0)
           { s+=np[i]+" "+gasP[i].toString(); }
       if(i!=(ngas-1) && np[i]!=0 ) s+=" + ";
       }
       if(s.endsWith(" + "))
         s=s.substring(0,s.length()-3);
     return s;
     }

     public String toString(String ch)
     {
     //return the c
     String s="";
     int i,j;
     if(ch.equals("name"))
        s=s+reacName+"\n";
     else if(ch.equals("formula"))
        {
        s=toString();
        }
     else if(ch.equals("composition"))
        {
        for(i=0;i<natom;i++)
        s=s+atomList[i].toString()+" ";
        }
     return s;
     }

     public double H(double TR,double TP)
     {
     //reaction enthalpy
      double HH=0;
      for(int i=0;i<ngas;i++)
      {
       HH+=gasP[i].HT(TP);
       HH-=gasR[i].HT(TR);
      }
      return HH;
     }

     public double S(double TR,double TP,double pt)
     {
     //reaction entropy
      double SS=0;
      for(int i=0;i<ngas;i++)
      {
       if(np[i]!=0)
          SS+=gasP[i].S(TP,np[i]/npt*pt);
       if(nr[i]!=0)
          SS-=gasR[i].S(TR,nr[i]/nrt*pt);
      }
      return SS;
     }

     public double S(double TR,double TP)
     {
     //reaction entropy
      double SS=0;
      for(int i=0;i<ngas;i++)
      {
       if(np[i]!=0)
          SS+=gasP[i].S(TP,np[i]/npt);
       if(nr[i]!=0)
          SS-=gasR[i].S(TR,nr[i]/nrt);
      }
      return SS;
     }

     public double G(double TR,double TP,double pt)
     {
     // reaction gibbs energy
      double GG=0;
      for(int i=0;i<ngas;i++)
      {
       if(np[i]!=0)
          GG+=gasP[i].GT(TP,np[i]/npt*pt);
       if(nr[i]!=0)
          GG-=gasR[i].GT(TR,nr[i]/nrt*pt);
      }
      return GG;
     }

     public double G(double TR,double TP)
     {
     // reaction gibbs energy
      double GG=0;
      for(int i=0;i<ngas;i++)
      {
       if(np[i]!=0)
          GG+=gasP[i].GT(TP,np[i]/npt);
       if(nr[i]!=0)
          GG-=gasR[i].GT(TR,nr[i]/nrt);
      }
      return GG;
     }

     public double G0(double TR,double TP)
     {
     // reaction gibbs free energy
      double GG=0;
      for(int i=0;i<ngas;i++)
      {
       if(np[i]!=0)
          GG+=gasP[i].GT(TP);
       if(nr[i]!=0)
          GG-=gasR[i].GT(TR);
      }
      return GG;
     }

     public double K(double TR,double TP)
     {
     //Equilibrium costant. Usually TR and Tp will be in
     // thesame temperature
     return Math.exp(G0(TR,TP)/(-8.3145*TP));
     }

     public double Taf(double TR,double xl,double xu)
     {
     // Adyabatic flame temperature using Bisection method
     // bisection method to find roots of zero energy change
     // Q=0
     // defination of variables :
     // xl : lower guess
     // xu : upper guess
     // xr : root estimate
     // es : stopping criterion
     // ea :approximate error
     // maxit : maximum iterations
     // iter  : number of iteration
     double test;
     double xr=0;
     double es,ea;
     double fxl,fxr;
     int maxit=500,iter=0;
     es=0.000001;
     ea=1.1*es;
     while((ea>es)&&(iter<maxit))
     {
     xr=(xl+xu)/2.0;
     iter++;
     if((xl+xu)!=0)
        { ea=Math.abs((xu-xl)/(xl+xu))*100;}
     fxl= H(TR,xl);
     fxr= H(TR,xr);
     test= fxl*fxr;
     if(test==0.0)       ea=0;
     else if(test<0.0)  xu=xr;
     else
       {
       xl=xr;
       }
     } //end of while
     return xr;
     }
  }


