/**
 * This class is transform input feature as Weka Model's Instance
 * @author B Han
 * @date 10 June 2010
 */

import java.io.*;
import weka.core.*;
// import weka.core.DenseInstance;

public class FeatureToInstance {
 	// int numOfFeature = 186;
	// int numOfFeature = 188;
	int numOfFeature = 183;

    // Instance denseinst = new DenseInstance(185);
	
	Instance inst;
    // Instances instances;
	
	private boolean DEBUG = ShiftXp.DEBUG;
    
    NormalizeFeatureRanges fr = new NormalizeFeatureRanges(); 
    
    public FeatureToInstance() {
    	// instances.setClassIndex(numOfFeature-1);
    	inst = new Instance(numOfFeature);   // weka.jar version 3.7.0 or 3.6.1
    	// inst = new DenseInstance(numOfFeature);  // weka.jar version 3.7.1
    	inst.setDataset(ShiftXp.predmodels.instanceHeader);
    }

    public FeatureToInstance(Residue res, Atom atom) {
	    //inst.setDataset;
    }

    // transform Chi angles if it is negative
    private double  nonNegativeChi(double angle) {
        return ( angle < 0 ? (360.0 + angle) : angle );
    }

    public double checkAngle(double angle) {
        return ( angle == -666 ? 0 : angle ); 
    }

    public void setNorm2Bin_Iupac(String iupac, int startpos) {
        if (iupac.equals("A") )       inst.setValue(startpos,   1);
        else if (iupac.equals("B") )  inst.setValue(startpos+1, 1);
        else if (iupac.equals("C") )  inst.setValue(startpos+2, 1);
        else if (iupac.equals("D") )  inst.setValue(startpos+3, 1);
        else if (iupac.equals("E") )  inst.setValue(startpos+4, 1);
        else if (iupac.equals("F") )  inst.setValue(startpos+5, 1);
        else if (iupac.equals("G") )  inst.setValue(startpos+6, 1);
        else if (iupac.equals("H") )  inst.setValue(startpos+7, 1);
        else if (iupac.equals("I") )  inst.setValue(startpos+8, 1);
        else if (iupac.equals("K") )  inst.setValue(startpos+9, 1);
        else if (iupac.equals("L") )  inst.setValue(startpos+10, 1);
        else if (iupac.equals("M") )  inst.setValue(startpos+11, 1);
        else if (iupac.equals("N") )  inst.setValue(startpos+12, 1);
        else if (iupac.equals("P") )  inst.setValue(startpos+13, 1);
        else if (iupac.equals("Q") )  inst.setValue(startpos+14, 1);
        else if (iupac.equals("R") )  inst.setValue(startpos+15, 1);
        else if (iupac.equals("S") )  inst.setValue(startpos+16, 1);
        else if (iupac.equals("T") )  inst.setValue(startpos+17, 1);
        else if (iupac.equals("V") )  inst.setValue(startpos+18, 1);
        else if (iupac.equals("W") )  inst.setValue(startpos+19, 1);
        else if (iupac.equals("Y") )  inst.setValue(startpos+20, 1);
        else inst.setValue(startpos+21, 1);
    }

    public void setNorm2Bin_ss(String ss, int startpos) {
        // values: B/C/H/NA
        if (ss.equals("B") )       inst.setValue(startpos,   1);
        else if (ss.equals("C") )  inst.setValue(startpos+1, 1);
        else if (ss.equals("H") )  inst.setValue(startpos+2, 1);
        else if (ss.equals("NA"))  inst.setValue(startpos+3, 1);
    }

  
    // without normalization, only norminal to binorminal
    public Instance setInstanceWithTransform(Residue res, Atom atom)   {
        
        // 1. dataset structure : empty arff
        // 2. create instance
        // 3. set Instance value : setValue(int attIndex, double value)

        // iupac: 1~21
        // iupac_p/n,p2/n2 : 1~22
        // ss: B,C,H,NA: 4

        // initialize attribute: iupac, iupac_p/n, p2/n2, ss, ss_p/n
        for (int i=0; i < this.numOfFeature-1; i++) inst.setValue(i, 0);

        setNorm2Bin_Iupac(res.iupac, 0); 
        setNorm2Bin_Iupac(res.iupac_p,  24); 
        setNorm2Bin_Iupac(res.iupac_n,  50); 
        setNorm2Bin_Iupac(res.iupac_p2, 76); 
        setNorm2Bin_Iupac(res.iupac_n2, 98); 
        setNorm2Bin_ss(res.ss,   21); 
        setNorm2Bin_ss(res.ss_p, 46); 
        setNorm2Bin_ss(res.ss_n, 72); 

        // note: index begins from zero(0), So actual index is needed to plus one for arff format 
        inst.setValue(120 , res.hbond);
        inst.setValue(121 , res.hbond_p);
        inst.setValue(122 , res.hbond_n);
        inst.setValue(123 , res.resASA); 
        inst.setValue(124 , res.fracASA);
      //  inst.setValue( , res.resVol);       // unused feature
      // inst.setValue(125 , res.fracVol);     // Now set zero - ununsed 
        inst.setValue(125 , res.sideASA);
        inst.setValue(126 , res.sideFracASA);
        inst.setValue(127 , res.SFE);
        inst.setValue(128 , res.phi);
        inst.setValue(129 , res.psi);
        inst.setValue(130 , res.omega);
        inst.setValue(131 , res.chi);
        inst.setValue(132 , res.chi2);
        inst.setValue(133 , res.chi3);
        inst.setValue(134 , res.phi_p);
        inst.setValue(135 , res.psi_p);
        inst.setValue(136 , res.omega_p);
        inst.setValue(137 , res.chi_p);
        inst.setValue(138 , res.phi_n);
        inst.setValue(139 , res.psi_n);
        inst.setValue(140 , res.omega_n);
        inst.setValue(141 , res.chi_n);
        inst.setValue(142 , res.phi_p2);
        inst.setValue(143 , res.psi_p2);
        inst.setValue(144 , res.omega_p2);
        inst.setValue(145 , res.chi_p2);
        inst.setValue(146 , res.phi_n2);
        inst.setValue(147 , res.psi_n2);
        inst.setValue(148 , res.omega_n2);
        inst.setValue(149 , res.chi_n2);
        inst.setValue(150 , nonNegativeChi(res.chi));   // nn chi
        inst.setValue(151 , nonNegativeChi(res.chi2));
        inst.setValue(152 , nonNegativeChi(res.chi3));
        inst.setValue(153 , nonNegativeChi(res.chi_p));
        inst.setValue(154 , nonNegativeChi(res.chi_n));
        inst.setValue(155 , nonNegativeChi(res.chi_p2));
        inst.setValue(156 , nonNegativeChi(res.chi_n2));
//        inst.setValue(157 , checkAngle(res.theta_donor));
//        inst.setValue(158 , checkAngle(res.kappa_donor));
//        inst.setValue(159 , checkAngle(res.theta_acceptor));
//        inst.setValue(160 , checkAngle(res.kappa_acceptor));
        inst.setValue(157 , res.dbond);
        inst.setValue(158 , res.dbond_p);
        inst.setValue(159 , res.dbond_n);
        inst.setValue(160 , res.ha1dist);
        inst.setValue(161 , res.ha2dist);
        // inst.setValue(162 , res.hndist);
        inst.setValue(162 , res.ordist);
        inst.setValue(163 , res.ha1dist_p);
        inst.setValue(164 , res.ha2dist_p);
        //inst.setValue(166 , res.hndist_p);
        inst.setValue(165 , res.ordist_p);
        inst.setValue(166 , res.ha1dist_n);
        inst.setValue(167 , res.ha2dist_n);
        //inst.setValue(170 , res.hndist_n);
        inst.setValue(168 , res.ordist_n);
        inst.setValue(169 , res.hydro);
        inst.setValue(170 , atom.asa);
        inst.setValue(171 , atom.rcoil);
        inst.setValue(172 , atom.rcurr);
        inst.setValue(173 , atom.electrostat);
        inst.setValue(174 , atom.hbondeffect);
        inst.setValue(175 , res.theta);
        inst.setValue(176 , res.kappa);
        inst.setValue(177 , res.ph);
        inst.setValue(178 , res.temperature);

        inst.setValue(179 , -9999); // predcs
        // inst.setValue(179 , atom.sxpred);  // only used to make training set (diff)

	    // same as feature saving modules 
        boolean savefeature = false;

        if (DEBUG && savefeature)  {
            try {
                FileWriter fos = new FileWriter( res.id+".featureNEW", true );
                // System.out.println(res.id+","+res.resNum+","+res.iupac+","+res.resName+","+atom.atomName+","+inst+"\n");
                fos.write(res.id+","+res.resNum+","+res.iupac+","+res.resName+","+atom.atomName+","+ inst+"\n");
                fos.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        
        return inst;
    }

    // with normalization after norminal to binorminal
    public Instance setInstanceWithNormalizeTransform(Residue res, Atom atom)   {
    	
        // 1. dataset structure : empty arff
        // 2. create instance
        // 3. set Instance value : setValue(int attIndex, double value)

        // iupac: 1~21
        // iupac_p/n,p2/n2 : 1~22
        // ss: B,C,H,NA: 4

        // initialize attribute: iupac, iupac_p/n, p2/n2, ss, ss_p/n
        for (int i=0; i < 185; i++) inst.setValue(i, 0);
        setNorm2Bin_Iupac(res.iupac, 0); 
        setNorm2Bin_Iupac(res.iupac_p,  24); 
        setNorm2Bin_Iupac(res.iupac_n,  50); 
        setNorm2Bin_Iupac(res.iupac_p2, 76); 
        setNorm2Bin_Iupac(res.iupac_n2, 98); 
        setNorm2Bin_ss(res.ss,   21); 
        setNorm2Bin_ss(res.ss_p, 46); 
        setNorm2Bin_ss(res.ss_n, 72); 
       
        // note: index begins from zero(0), So actual index is needed to plus one  
        inst.setValue(120 , res.hbond);
        inst.setValue(121 , res.hbond_p);
        inst.setValue(122 , res.hbond_n);
        inst.setValue(123 , fr.getNormalizeFeature("resASA",      res.resASA)); 
        inst.setValue(124 , fr.getNormalizeFeature("fracASA",     res.fracASA));
      //  inst.setValue( , res.resVol);
        inst.setValue(125 , fr.getNormalizeFeature("fracVol",     res.fracVol));
        inst.setValue(126 , fr.getNormalizeFeature("sideASA",     res.sideASA));
        inst.setValue(127 , fr.getNormalizeFeature("sideFracASA", res.sideFracASA));
        inst.setValue(128 , fr.getNormalizeFeature("SFE",         res.SFE));
        inst.setValue(129 , fr.getNormalizeFeature("phi",         checkAngle(res.phi)));
        inst.setValue(130 , fr.getNormalizeFeature("psi",         checkAngle(res.psi)));
        inst.setValue(131 , fr.getNormalizeFeature("omega",       checkAngle(res.omega)));
        inst.setValue(132 , fr.getNormalizeFeature("chi",         checkAngle(res.chi)));
        inst.setValue(133 , fr.getNormalizeFeature("chi2",        checkAngle(res.chi2)));
        inst.setValue(134 , fr.getNormalizeFeature("chi3",        checkAngle(res.chi3)));
        inst.setValue(135 , fr.getNormalizeFeature("phi_p",       checkAngle(res.phi_p)));
        inst.setValue(136 , fr.getNormalizeFeature("psi_p",       checkAngle(res.psi_p)));
        inst.setValue(137 , fr.getNormalizeFeature("omega_p",     checkAngle(res.omega_p)));
        inst.setValue(138 , fr.getNormalizeFeature("chi_p",       checkAngle(res.chi_p)));
        inst.setValue(139 , fr.getNormalizeFeature("phi_n",       checkAngle(res.phi_n)));
        inst.setValue(140 , fr.getNormalizeFeature("psi_n",       checkAngle(res.psi_n)));
        inst.setValue(141 , fr.getNormalizeFeature("omega_n",     checkAngle(res.omega_n)));
        inst.setValue(142 , fr.getNormalizeFeature("chi_n",       checkAngle(res.chi_n)));
        inst.setValue(143 , fr.getNormalizeFeature("phi_p2",      checkAngle(res.phi_p2)));
        inst.setValue(144 , fr.getNormalizeFeature("psi_p2",      checkAngle(res.psi_p2)));
        inst.setValue(145 , fr.getNormalizeFeature("omega_p2",    checkAngle(res.omega_p2)));
        inst.setValue(146 , fr.getNormalizeFeature("chi_p2",      checkAngle(res.chi_p2)));
        inst.setValue(147 , fr.getNormalizeFeature("phi_n2",      checkAngle(res.phi_n2)));
        inst.setValue(148 , fr.getNormalizeFeature("psi_n2",      checkAngle(res.psi_n2)));
        inst.setValue(149 , fr.getNormalizeFeature("omega_n2",    checkAngle(res.omega_n2)));
        inst.setValue(150 , fr.getNormalizeFeature("chi_n2",      checkAngle(res.chi_n2)));
        inst.setValue(151 , fr.getNormalizeFeature("chi",         nonNegativeChi(checkAngle(res.chi))));   // nn chi
        inst.setValue(152 , fr.getNormalizeFeature("chi2",        nonNegativeChi(checkAngle(res.chi2))));
        inst.setValue(153 , fr.getNormalizeFeature("chi3",        nonNegativeChi(checkAngle(res.chi3))));
        inst.setValue(154 , fr.getNormalizeFeature("chi_p",       nonNegativeChi(checkAngle(res.chi_p))));
        inst.setValue(155 , fr.getNormalizeFeature("chi_n",       nonNegativeChi(checkAngle(res.chi_n))));
        inst.setValue(156 , fr.getNormalizeFeature("chi_p2",      nonNegativeChi(checkAngle(res.chi_p2))));
        inst.setValue(157 , fr.getNormalizeFeature("chi_n2",      nonNegativeChi(checkAngle(res.chi_n2))));
        inst.setValue(158 , fr.getNormalizeFeature("theta_donor",    checkAngle(res.theta_donor)));
        inst.setValue(159 , fr.getNormalizeFeature("kappa_donor",    checkAngle(res.kappa_donor)));
        inst.setValue(160 , fr.getNormalizeFeature("theta_acceptor", checkAngle(res.theta_acceptor)));
        inst.setValue(161 , fr.getNormalizeFeature("kappa_acceptor", checkAngle(res.kappa_acceptor)));
        inst.setValue(162 , res.dbond);
        inst.setValue(163 , res.dbond_p);
        inst.setValue(164 , res.dbond_n);
        inst.setValue(165 , fr.getNormalizeFeature("ha1dist",   res.ha1dist));
        inst.setValue(166 , fr.getNormalizeFeature("ha2dist",   res.ha2dist));
        inst.setValue(167 , fr.getNormalizeFeature("hndist",    res.hndist));
        inst.setValue(168 , fr.getNormalizeFeature("ordist",    res.ordist));
        inst.setValue(169 , fr.getNormalizeFeature("ha1dist_p", res.ha1dist_p));
        inst.setValue(170 , fr.getNormalizeFeature("ha2dist_p", res.ha2dist_p));
        inst.setValue(171 , fr.getNormalizeFeature("hndist_p",  res.hndist_p));
        inst.setValue(172 , fr.getNormalizeFeature("ordist_p",  res.ordist_p));
        inst.setValue(173 , fr.getNormalizeFeature("ha1dist_n", res.ha1dist_n));
        inst.setValue(174 , fr.getNormalizeFeature("ha2dist_n", res.ha2dist_n));
        inst.setValue(175 , fr.getNormalizeFeature("hndist_n",  res.hndist_n));
        inst.setValue(176 , fr.getNormalizeFeature("ordist_n",  res.ordist_n));
        inst.setValue(177 , fr.getNormalizeFeature("hydro",     res.hydro));
        inst.setValue(178 , fr.getNormalizeFeature("asa",       atom.asa));
        inst.setValue(179 , fr.getNormalizeFeature("rcoil",     atom.rcoil));
        inst.setValue(180 , fr.getNormalizeFeature("rcurr",     atom.rcurr));
        inst.setValue(181 , fr.getNormalizeFeature("electrostat", atom.electrostat));
        inst.setValue(182 , fr.getNormalizeFeature("hbondeffect", atom.hbondeffect));
        inst.setValue(183 , fr.getNormalizeFeature("ph", res.ph));
        inst.setValue(184 , fr.getNormalizeFeature("temperature", res.temperature));

        // inst.setValue(185 , (atom.rcoil+atom.rcurr+atom.electrostat+atom.hbondeffect) );  // it has no effect, so it will be removed
        inst.setValue(185 , -9999);
        
        System.out.println(inst);
        
        if (DEBUG)  {        
	        try {
	           FileWriter fos = new FileWriter( res.id+".feature", true );
	           fos.write(res.id+","+res.resNum+","+res.iupac+","+res.resName+","+atom.atomName+","+ inst +"\n");
	           fos.close();
	        } catch (IOException ex) {
	           ex.printStackTrace();
	        }
        }
        
         return inst;
    }

}


