import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import lpsolve.*;
import lt.ktu.diet.Exchange;
import lt.ktu.diet.common.Constants;

public class DietaServlet extends HttpServlet {
	private short LE = 1;
	private short GE = 2;

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			Exchange data = new Exchange();

			InputStream in = request.getInputStream();
			ObjectInputStream ois = new ObjectInputStream(in);
			data = (Exchange) ois.readObject();			

			LpSolve lp;
			try {
				lp = LpSolve.makeLp(0, data.activProdCnt);

				for (int i = 1; i <= data.activProdCnt; i++)
					if (data.prodActiv[i].getDish() == 1) { // jei patiekalas			
						lp.setInt(i, true);
						lp.setUpbo(i, Constants.maxPatiekaluKiekis);
					} else { // jei ne patiekalas
						lp.setInt(i, false);
					}

				double rhs;

				// Optimizuojama pagal kaina, ribojimus nusako kalorijos (ju skaiciu galima keisti pagal "grozio" faktoriu), baltymai,riebalai ir kt.
				// skonio faktorius veikia kaina 10%, juo didesnis skonis tuo daugiau norima uz preke moketi, t.y. kaina mazeja didejant skoniui
				// Tikslo funkcija: minx->sum((ci-si)+g*ai1-d*di)xi-g*b1.
				// g*b1 galima praleisti, nes jis vienodas visiems patiekalams
				// ci - produkto kg/vnt kaina,
				// si - skonio "kaina",
				// g - grozio faktorius,
				// di - maisto ivairoves (diversity) faktorius:
				// di = 1 - jei i-tasisi produktas yra patiekalas, kitu atveju di = 0
				// b1 - kaloriju norma						

				//double mytest = 0;				
				double correction = 0;
				for (int i = 1; i <= data.activProdCnt; i++) { // 90(84) formule vienam produktui

					/* SAULIUS 2010-03-28 senesn� formul�
							  		data[i] = ((prodActiv[i].price - prodActiv[i].price * prodActiv[i].Taste * Constants.tasteIndex) + 
									BeautyFactor * tmpDienos *prodActiv[i].calories - fMaistoIvairumas.doubleValue()
					 * prodActiv[i].getDish());
					 */					

					// SAULIUS 2010-03-28 "correction" suvienodina matavimo vienetus produktams, kad b�t� Lt/100g ir kcal/100g
					if (data.prodActiv[i].getDish() == 1)
						correction = 1; 
					else 
						correction = 0.1;

					data.data[i] = ((data.prodActiv[i].getPrice() - data.prodActiv[i].getPrice() * data.prodActiv[i].getTaste() * Constants.tasteIndex) 
							+ correction * data.BeautyFactor * data.prodActiv[i].getCalories()
							- data.fMaistoIvairumas.doubleValue()* data.prodActiv[i].getDish());						

					//mytest = mytest + (prodActiv[i].price - prodActiv[i].price * prodActiv[i].Taste * Constants.tasteIndex);

					if (data.data[i] < -10000) { // labai mazas skaicius, rezultate gausime nesamone
						data.opt_func_salyga = 1; // skaiciavimu neatliksime
					}
				}	

				if (data.opt_func_salyga != 1) {
					lp.setObjFn(data.data);
					lp.setMinim();

					/* Calories */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getCalories();
					//apatine riba
					rhs = (data.Cal - data.Cal * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.lowerTolCalories;
					lp.addConstraint(data.data, GE, rhs);
					//virsutine riba
					rhs = (data.Cal + data.Cal * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.upperTolCalories;
					lp.addConstraint(data.data, LE, rhs);

					/* Proteins */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getProteins();
					rhs = (data.Pro - data.Pro * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.lowerTolProteins;
					lp.addConstraint(data.data, GE, rhs);
					rhs = (data.Pro + data.Pro * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.upperTolProteins;
					lp.addConstraint(data.data, LE, rhs);

					/* Fats */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getFats();
					rhs = (data.Fat - data.Fat * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.lowerTolFats;
					lp.addConstraint(data.data, GE, rhs);
					rhs = (data.Fat + data.Fat * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.upperTolFats;
					lp.addConstraint(data.data, LE, rhs);

					/* Carbohydrates */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getCarbohydrates();
					//rhs = (tmpDienos *Car - Car * Paklaida) * weight2 * Constants.lowerTolCarbohydrates;
					rhs = (data.Car - data.Car * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.lowerTolCarbohydrates;
					lp.addConstraint(data.data, GE, rhs);
					rhs = (data.Car + data.Car * data.Paklaida) * data.tmpDienos * data.weight2 * Constants.upperTolCarbohydrates;
					lp.addConstraint(data.data, LE, rhs);

					/* mikroelementai ir vitaminai pateikiami fiksuota dienos norma zmogui */

					/* vit A */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitA();
					rhs = (data.VitA - data.VitA * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitA;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitA + VitA * Paklaida) * Constants.upperTolVitA;

					/* vit B1 */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitB1();
					rhs = (data.VitB1 - data.VitB1 * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitB1;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitB1 + VitB1 * Paklaida) * Constants.upperTolVitB1;
					//lpSolve.add_constraint_up(lpRec, data, LE, rhs);

					/* vit B2 */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitB2();
					rhs = (data.VitB2 - data.VitB2 * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitB2;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitB2 + VitB2 * Paklaida) * Constants.upperTolVitB2;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* vit B3 */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitB3();
					rhs = (data.VitB3 - data.VitB3 * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitB3;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitB3 + VitB3 * Paklaida) * Constants.upperTolVitB3;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* vit B6 */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitB6();
					rhs = (data.VitB6 - data.VitB6 * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitB6;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitB6 + VitB6 * Paklaida) * Constants.upperTolVitB6;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* vit B12 */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitB12();
					rhs = (data.VitB12 - data.VitB12 * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitB12;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitB12 + VitB12 * Paklaida) * Constants.upperTolVitB12;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* vit C */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitC();
					rhs = (data.VitC - data.VitC * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitC;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitC + VitC * Paklaida) * Constants.upperTolVitC; 
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* vit E */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitE();
					rhs = (data.VitE - data.VitE * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitE;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitE + VitE * Paklaida) * Constants.upperTolVitE;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* vit PP */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getVitPP();
					rhs = (data.VitPP - data.VitPP * data.Paklaida) * data.tmpDienos * Constants.lowerTolVitPP;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (VitPP + VitPP * Paklaida) * Constants.upperTolVitPP;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* mikrel Ca */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getMinCa();
					rhs = (data.MinCa - data.MinCa * data.Paklaida) * data.tmpDienos * Constants.lowerTolMikrelCa;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (MinCa + MinCa * Paklaida) * Constants.upperTolMikrelCa;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* mikrel Na */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getMinNa();
					rhs = (data.MinNa - data.MinNa * data.Paklaida) * data.tmpDienos * Constants.lowerTolMikrelNa;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (MinNa + MinNa * Paklaida) * Constants.upperTolMikrelNa;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* mikrel S */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getMinS();
					rhs = (data.Siera - data.Siera * data.Paklaida) * data.tmpDienos * Constants.lowerTolMikrelS;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (Siera + Siera * Paklaida) * Constants.upperTolMikrelS;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* mikrel P */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getMinP();
					rhs = (data.Fosf - data.Fosf * data.Paklaida) * data.tmpDienos * Constants.lowerTolMikrelP;
					lp.addConstraint(data.data, GE, rhs);
					//rhs = (Fosf + Fosf * Paklaida) * Constants.upperTolMikrelP;
					//lpSolve.add_constraint(lpRec, data, LE, rhs);

					/* Liquids */
					for (int i = 1; i <= data.activProdCnt; i++)
						data.data[i] = data.prodActiv[i].getLiquid();
					rhs = (data.Liquid - data.Liquid * data.Paklaida) * data.tmpDienos * Constants.lowerTolFluid;
					lp.addConstraint(data.data, GE, rhs);
					rhs = (data.Liquid + data.Liquid * data.Paklaida) * data.tmpDienos * Constants.upperTolLiquid;
					lp.addConstraint(data.data, LE, rhs);					

					lp.writeLp("E:\\Inbox\\write_LP_new.txt");						

					data.UpVitC = data.tmpDienos *data.VitC * Constants.upperTolVitC;
					data.UpVitA = data.tmpDienos *data.VitA * Constants.upperTolVitA;
					data.UpMinCa = data.tmpDienos *data.MinCa * Constants.upperTolMikrelCa;
					data.UpMinNa = data.tmpDienos *data.MinNa * Constants.upperTolMikrelNa;
					data.UpVitE = data.tmpDienos *data.VitE * Constants.upperTolVitE;
					data.UpVitB1 = data.tmpDienos *data.VitB1 * Constants.upperTolVitB1;
					data.UpVitB2 = data.tmpDienos *data.VitB2 * Constants.upperTolVitB2;
					data.UpVitB3 = data.tmpDienos *data.VitB3 * Constants.upperTolVitB3;
					data.UpVitB6 = data.tmpDienos *data.VitB6 * Constants.upperTolVitB6;
					data.UpVitB12 = data.tmpDienos *data.VitB12 * Constants.upperTolVitB12;
					data.UpVitPP = data.tmpDienos *data.VitPP * Constants.upperTolVitPP;
					data.UpFosf = data.tmpDienos *data.Fosf * Constants.upperTolMikrelP;
					data.UpSiera = data.tmpDienos *data.Siera * Constants.upperTolMikrelS;
					data.UpLiquid = data.tmpDienos *data.Liquid * Constants.upperTolLiquid;

					data.rez = lp.solve();					    	

					if (data.rez == 0) {
						double nn = 0;
						int sk = 0;							

						// 0 - tikslo funkcijos reiksme
						// 1 iki Nrows - apribojimai
						// Nrows + 1 iki Nrows + Ncolumns + 1 - kintamuju reiksmes
						int el = 1+lp.getNrows() + lp.getNcolumns();
						double ss[] = new double[el];						
						lp.getPrimalSolution(ss);

						for (int i = 1+lp.getNrows(); i<el; i++)
						{
							if (ss[i] > 0) sk++;
						}

						data.rezai = new String[sk];
						int nr = 0;
						data.VitC = data.VitA = data.MinCa = data.MinNa = data.VitE = data.VitB1 = data.VitB2 = data.VitB3 = data.VitB6 = data.VitB12 = data.VitPP = data.Fosf = data.Siera = data.J = data.Liquid = 0.0;

						// per visus stulpelius	
						for (int i = 1+lp.getNrows(); i<el; i++)
						{
							int index = i - lp.getNrows();
							if (ss[i] > 0)
							{
								if (data.prodActiv[index].getDish() == 1)
									data.rezai[nr] = data.prodActiv[index].getName() + "," + Integer.toString((int)ss[i]) + " vnt"; //+ Integer.toString((int)lpSolve.get_lpsolution(lpRec, rows + i))
								else
									data.rezai[nr] = data.prodActiv[index].getName() + "," + Double.toString(ss[i]*10) + " 100g"; //+ Double.toString(lpSolve.get_lpsolution(lpRec, rows + i)*10)
								data.sumcal += ss[i] * (double) data.prodActiv[index].getCalories();
								data.sumpro += ss[i] * (double) data.prodActiv[index].getProteins();
								data.sumfat += ss[i] * (double) data.prodActiv[index].getFats();
								data.sumcar += ss[i] * (double) data.prodActiv[index].getCarbohydrates();
								data.sumak += ss[i] * (double) data.prodActiv[index].getPrice();
								data.sumaks += ss[i] * ((double) data.prodActiv[index].getPrice() - (double) data.prodActiv[index].getPrice() * (double) data.prodActiv[index].getTaste() * Constants.tasteIndex);
								data.VitC += ss[i] * (double) data.prodActiv[index].getVitC();
								data.VitA += ss[i] * (double) data.prodActiv[index].getVitA();
								data.MinCa += ss[i] * (double) data.prodActiv[index].getMinCa();
								data.MinNa += ss[i] * (double) data.prodActiv[index].getMinNa();
								data.VitE += ss[i] * (double) data.prodActiv[index].getVitE();
								data.VitB1 += ss[i] * (double) data.prodActiv[index].getVitB1();
								data.VitB2 += ss[i] * (double) data.prodActiv[index].getVitB2();
								data.VitB3 += ss[i] * (double) data.prodActiv[index].getVitB3();
								data.VitB6 += ss[i] * (double) data.prodActiv[index].getVitB6();
								data.VitB12 += ss[i] * (double) data.prodActiv[index].getVitB12();
								data.VitPP += ss[i] * (double) data.prodActiv[index].getVitPP();
								data.Fosf += ss[i] * (double) data.prodActiv[index].getMinP();
								data.Siera += ss[i] * (double) data.prodActiv[index].getMinS();
								data.J += ss[i] * (double) data.prodActiv[index].getMinJ();
								data.Liquid += ss[i] * (double) data.prodActiv[index].getLiquid();
								data.ivairove += ss[i] * data.prodActiv[index].getDish();
								nr++;
								data.mase += ss[i];
							}
						}	   					

					}
				}

			} catch (LpSolveException e) {
				e.printStackTrace();
			} 

			OutputStream out = response.getOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(out);
			oos.writeObject(data);
			oos.flush();

			oos.close();
			ois.close();
		} catch (Exception e) {
			outputSomething(e.toString());
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request,response);
	} 

	public void outputSomething(String s)
	{
		try {
			FileWriter outFile = new FileWriter("E:\\Inbox\\testing.txt");
			PrintWriter out = new PrintWriter(outFile);
			out.println(s);
			out.close();

		} catch (Exception e) {
			e.printStackTrace();          
		}
	}
}