package kz.locust.CCALM; //Главная

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
//import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

//import org.apache.commons.fileupload.FileItem;
//import org.apache.commons.fileupload.disk.DiskFileItemFactory;
//import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.CharacterData;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;

import tctable.Tools;
import tools.EmailUtility;
import tools.User;


@Controller
@SessionAttributes( { "user" }) //Сесионный объект
public class DBMSRecords implements ServletContextAware {

	//private static final Logger logger = LoggerFactory.getLogger(Translation.class);
	private static final Logger logger = LoggerFactory.getLogger(DBMSRecords.class);
	private ServletContext context;
	private Properties m_props=null;
	private String m_props_loc="";
	
	//If not created object "user", create him.
	@ModelAttribute("user")
	public User populatePerson() {
		return new User("none");
	}

	//Документация по @RequestBody http://javastudy.ru/spring-mvc/json-xml/

    @RequestMapping(value = "/records",method = RequestMethod.POST,produces = "application/xml; charset=utf-8")
    @ResponseBody
    public Object ajaxTamer(@ModelAttribute User user,@RequestBody byte[] reqData,@RequestParam(required=false,name="lng") String language_id) {
    	
    	if(language_id!=null && !language_id.equals("")) 
    		user.language_id=language_id;
    	logger.info("user.id="+user.id+" user.name="+user.name+" user.language_id="+user.language_id+" user.country_id="+user.country_id);
    	
    	boolean error=false;
    	String result="<metadata fn=\"-1\"><![CDATA[Request not processed!]]></metadata>";
		//response.setCharacterEncoding("UTF-8");

		//response.getWriter().append("Served at: ").append(request.getContextPath());
		//Thread.sleep(5000); // sleep 5 seconds
		//String metadata_file = "";
		String db_url = "";
		String db_login = "";
		String db_password = "";
		String mail_host = "";
		String mail_port = "";
		String mail_login = "";
		String mail_password = "";
		String data_dir = "";
		//Load DB configuration from "config.xml"
		try {
			//String fullPath = context.getRealPath("/WEB-INF/config.xml");
			//File fXmlFile = new File(fullPath);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			//Document doc = dBuilder.parse(fXmlFile);
			Document doc = dBuilder.parse(new ClassPathResource("config.xml").getInputStream());		
			Element nMain = doc.getDocumentElement();
			NodeList nl = nMain.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				if (nl.item(i).getNodeName().equals("db-url"))
					db_url = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("db-login"))
					db_login = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("db-password"))
					db_password = nl.item(i).getTextContent();

				if (nl.item(i).getNodeName().equals("mail-host"))
					mail_host = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("mail-port"))
					mail_port = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("mail-login"))
					mail_login = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("mail-password"))
					mail_password = nl.item(i).getTextContent();

				//if (nl.item(i).getNodeName().equals("metadata"))
				//	metadata_file = nl.item(i).getTextContent();
				
				if (nl.item(i).getNodeName().equals("data-dir"))
					data_dir = nl.item(i).getTextContent();
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
		}

		String jspPath = context.getRealPath("/");

		String fn = "";//request.getParameter("fn");
		String name = "";//request.getParameter("n"); //type name
		
		InputStream body = new ByteArrayInputStream(reqData);

		//logger.info("Send \"Records\" for user = ."+user.name);
		//logger.info("req = "+req);

		Document doc = null;
		Element reqNode = null;
		try {
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			doc = dBuilder.parse(body);
		} catch (Exception ex) {
			logger.info(ex.getMessage());
			return "<metadata fn=\"-1\"><![CDATA[Parsing request error!]]></metadata>";
		}

		if (doc != null) {
			reqNode = doc.getDocumentElement();
			fn = reqNode.getAttribute("fn"); //Номер функции
		}

		//logger.info("");
		//logger.info("XML = ");
		//logger.info(toString(doc));

		Connection conn = null;
		try {
			Class.forName("org.postgresql.Driver");
			conn = DriverManager.getConnection(db_url, db_login, db_password);
			if (conn != null) {
				logger.info("Connect is OK!");
			} else {
		    	error=true;
		    	result="<metadata fn=\"-1\"><![CDATA[An error occurred while connecting to the database!]]></metadata>";
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
	    	error=true;
	    	result="<metadata fn=\"-1\"><![CDATA[An error occurred while connecting to the database!]]></metadata>";
		}

		try {
			Statement stt0 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
			//st.executeUpdate("SET TIME ZONE 'UTC';"); зачем коментил?
			stt0.executeUpdate("SET TIME ZONE 'Asia/Almaty';");
			stt0.close();
		} catch (SQLException ex) {
			logger.info(ex.getMessage());
			error=true;
			result="<metadata fn=\"-1\"><![CDATA[An set TYPE_SCROLL_SENSITIVE!]]></metadata>";			
		}

		//response.getWriter().append("fn="+fn);
		//out.print("<br>"+ request.getRequestURI() );

		//XPathFactory xPathfactory = XPathFactory.newInstance(); //If error set path in tomcat to xalan.jar
		javax.xml.xpath.XPathFactory xPathfactory = javax.xml.xpath.XPathFactory.newInstance();
		XPath xpath = xPathfactory.newXPath();
		XPathExpression expr=null;

		//Description
		// (Fn == 0) - Send the metadata to the client at the requested site
		// (Fn == 1) - Insert one record in the database
		// (Fn == 2) - Update the record
		// (Fn == 3) - Delete the record
		// (Fn == 4) - Send data to the client according to the filter value
		// (Fn == 5) - Take the data for editing 1st record by id
		// (Fn == 6) - Return the data to the client to fill SELECT object into a separate function to save bandwidth filters can also be used here
		// (Fn == 7) - Login (or sent restore email)
		// (Fn == 8) - Reports almost the same as the function 4
		// (Fn == 9) - Save the binary data into the database

		if (fn != null && fn.equals("0")) //Send metadata to client
		{
			if (doc != null) {
				xPathfactory = XPathFactory.newInstance();
				xpath = xPathfactory.newXPath();
				try {
					expr = xpath.compile("//metadata/type/@n");
					name = "" + expr.evaluate(doc, XPathConstants.STRING);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
					error=true;
				}
			}

			String xml = "";

			//Get XML node from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,name));

			if (doc != null) {
				doc.getDocumentElement().normalize(); //Del or concat text node

				xml += "<metadata fn=\"0\">";

				//Delete all child "sql-query" nodes.
				XPathExpression exp=null;
				NodeList nl=null;
				try {
					exp = xpath.compile("//sql-query");
					nl = (NodeList) exp.evaluate(doc, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				
				for (int j = 0; j < nl.getLength(); j++) {
					nl.item(j).getParentNode().removeChild(nl.item(j));
				}
				// XML Node Serialisation
				DOMImplementationLS domImplementation = (DOMImplementationLS) doc.getImplementation();
				LSSerializer lsSerializer = domImplementation.createLSSerializer();
				lsSerializer.getDomConfig().setParameter("xml-declaration", false);

				//Set attributes to define access level (insert,update,selete,select).
				String sql_query = "";
				String allow;
				Statement stt=null;
				ResultSet rs=null;

				allow = "1";
				try {
					stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					sql_query = "select main.p_getAccess(" + user.id + ", 'Select_" + name + "') as acc;";
					rs = stt.executeQuery(sql_query);
					if (rs != null) {
						try {
							if (rs.next())
								if (rs.getBoolean(1))
									allow = "1";
								else
									allow = "0";
							rs.close();
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}
					}
				} catch (SQLException ex) {
					logger.info(ex.getMessage() + " SQL=" + sql_query);
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
					error=true;
				}finally {
					if(rs!=null) try{rs.close();}catch(SQLException ex){}
					if(stt!=null) try{stt.close();}catch(SQLException ex){}
				}
				doc.getDocumentElement().setAttribute("sel", allow);

				stt=null; rs=null;
				allow = "1";
				try {
					stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					rs = stt.executeQuery("select main.p_getAccess(" + user.id + ", 'Insert_" + name + "') as acc;");
					if (rs != null) {
						try {
							if (rs.next())
								if (rs.getBoolean(1))
									allow = "1";
								else
									allow = "0";
							rs.close();
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}
					}
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
					error=true;
				}finally {
					if(rs!=null) try{rs.close();}catch(SQLException ex){}
					if(stt!=null) try{stt.close();}catch(SQLException ex){}
				}
				doc.getDocumentElement().setAttribute("ins", allow);

				stt=null; rs=null;
				allow = "1";
				try {
					stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					rs = stt.executeQuery("select main.p_getAccess(" + user.id + ", 'Update_" + name + "') as acc;");
					if (rs != null) {
						try {
							if (rs.next())
								if (rs.getBoolean(1))
									allow = "1";
								else
									allow = "0";
							rs.close();
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}						
					}
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
					error=true;
				}finally {
					if(rs!=null) try{rs.close();}catch(SQLException ex){}
					if(stt!=null) try{stt.close();}catch(SQLException ex){}
				}
				doc.getDocumentElement().setAttribute("upd", allow);

				stt=null; rs=null;
				allow = "1";
				try {
					stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					rs = stt.executeQuery("select main.p_getAccess(" + user.id + ", 'Delete_" + name + "') as acc;");
					if (rs != null) {
						try {
							if (rs.next())
								if (rs.getBoolean(1))
									allow = "1";
								else
									allow = "0";
							rs.close();
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}
					}
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
					error=true;
				}finally {
					if(rs!=null) try{rs.close();}catch(SQLException ex){}
					if(stt!=null) try{stt.close();}catch(SQLException ex){}
				}
				doc.getDocumentElement().setAttribute("del", allow);

				xml += lsSerializer.writeToString(doc.getDocumentElement());
				xml += "</metadata>";
			} else {
				xml += "<metadata fn=\"0\"></metadata>";
			}

			result=getText(conn,xml,user);

		} else if (fn != null && fn.equals("1")) {
			String typename = "";
			String obj_id = "";
			NodeList node_properties = null;

			Node nTypeR = null;
			if (doc != null) {
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);

					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					//obj_id = "" + nTypeR.getAttributes().getNamedItem("id").getNodeValue();  //The current page number
					try {
						expr = xpath.compile("properties/prop");
						node_properties = (NodeList) expr.evaluate(nTypeR, XPathConstants.NODESET);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			if (doc != null) {
				//doc.getDocumentElement().normalize(); //Del or concat text node
				Node nTypeS = doc.getDocumentElement();

				String sql_query="";
				try {
					expr = xpath.compile("properties/sql-query[@t='i']/text()");
					sql_query = (String) expr.evaluate(nTypeS, XPathConstants.STRING);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}				

				logger.info("sql_query11 = " + sql_query);

				for (int i = 0; i < node_properties.getLength(); i++) {
					String vn = node_properties.item(i).getAttributes().getNamedItem("n").getNodeValue();
					String val = node_properties.item(i).getTextContent();

					//Since the node type does not appear in the query, we select it separately
					String vt = "";
					NodeList nodeList=null;
					try {
						expr = xpath.compile("properties/prop[@n='" + vn + "']");
						nodeList = (NodeList) expr.evaluate(nTypeS, XPathConstants.NODESET);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}
					if (nodeList!=null && nodeList.getLength() > 0) {
						vt = nodeList.item(0).getAttributes().getNamedItem("vt").getNodeValue();
						//If this "file" is then copy it from the temporary folder to the specified path
						if(vt.equals("file")) 
						{
							String srcPath = data_dir;//context.getInitParameter("file-upload");
							String destPath = nodeList.item(0).getAttributes().getNamedItem("path").getNodeValue();
				            File srcFile = new File(srcPath+val); //Upload folder
				            if(srcFile.isFile())
				            {
				            	File destFile = new File(destPath+val); //Foldef from metadata.xml  
				            	try {
									FileUtils.copyFile(srcFile, destFile);
					            	FileUtils.forceDelete(srcFile);
								} catch (IOException ex) {
									logger.info(ex.getMessage());
								}
				            }
						}
					}

					sql_query = Tools.replaceAll(sql_query,"${" + vn + "}", getSQLValue(vt, val));

				}
				sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id in sql query.

				logger.info("sql_query22 = " + sql_query);

				try {
					Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					ResultSet rs = stt.executeQuery(sql_query);
					if (rs != null) {
						try {
							if (rs.next())
								obj_id = rs.getString(1);
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}
						String xmlstring = "<metadata fn=\"1\"><type n=\"" + typename + "\" id=\"" + obj_id + "\"></type></metadata>";

						result=xmlstring;
						logger.info("xmlstring = " + xmlstring);
					}
					stt.close();
					rs.close();
					stt=null;
					rs=null;
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
					error=true;
				}
			}

		} else if (fn != null && fn.equals("2")) //Update record by ID from XML data 
		{
			String typename = "";
			String obj_id = "";
			NodeList node_properties = null;

			Node nTypeR = null;
			if (doc != null) {
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);

					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					obj_id = "" + nTypeR.getAttributes().getNamedItem("id").getNodeValue(); //The current page number
					try {
						expr = xpath.compile("properties/prop");
						node_properties = (NodeList) expr.evaluate(nTypeR, XPathConstants.NODESET);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			if (doc != null) {
				//doc.getDocumentElement().normalize(); //Del or concat text node
				Node nTypeS = doc.getDocumentElement();

				String sql_query="";
				try {
					expr = xpath.compile("properties/sql-query[@t='u']/text()");
					sql_query = (String) expr.evaluate(nTypeS, XPathConstants.STRING);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}

				logger.info("sql_query = " + sql_query);
				for (int i = 0; i < node_properties.getLength(); i++) {
					String vn = node_properties.item(i).getAttributes().getNamedItem("n").getNodeValue();
					String val = node_properties.item(i).getTextContent();

					//Так как тип узла не передётся в запросе выбираем его отдельно
					String vt = "";
					NodeList nodeList = null;
					try {
						expr = xpath.compile("properties/prop[@n='" + vn + "']");
						nodeList = (NodeList) expr.evaluate(nTypeS, XPathConstants.NODESET);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}
					if (nodeList!=null && nodeList.getLength() > 0) {
						vt = nodeList.item(0).getAttributes().getNamedItem("vt").getNodeValue();
						//If this "file" is then copy it from the temporary folder to the specified path
						if(vt.equals("file")) 
						{
							String srcPath = data_dir;//context.getInitParameter("file-upload");
							String destPath = nodeList.item(0).getAttributes().getNamedItem("path").getNodeValue();
				            File srcFile = new File(srcPath+val); //Upload folder
				            if(srcFile.isFile())
				            {
				            	File destFile = new File(destPath+val); //Foldef from metadata.xml  
				            	try {
									FileUtils.copyFile(srcFile, destFile);
					            	FileUtils.forceDelete(srcFile);
								} catch (IOException ex) {
									logger.info(ex.getMessage());
								}

				            }
						}
					}
					sql_query=Tools.replaceAll(sql_query,"${" + vn + "}", getSQLValue(vt, val));
				}
				sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id in sql query.

				logger.info("sql_query = " + sql_query);

				try {
					Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					ResultSet rs = stt.executeQuery(sql_query);
					if (rs != null) {
						try {
							if (rs.next())
								obj_id = rs.getString(1);
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}

						String xmlstring = "<metadata fn=\"2\"><type n=\"" + typename + "\" id=\"" + obj_id + "\"></type></metadata>";

						result=xmlstring;
						logger.info("xmlstring = " + xmlstring);
					}
					rs.close();
					stt.close();
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
					error=true;
				}
			}

		} else if (fn != null && fn.equals("3")) {
			String typename = "";
			String obj_id = "";
			//NodeList node_properties=null;

			Node nTypeR = null;
			if (doc != null) {
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);

					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					obj_id = "" + nTypeR.getAttributes().getNamedItem("id").getNodeValue(); //The current page number

					//expr = xpath.compile("properties/prop");
					//node_properties = (NodeList)expr.evaluate(nTypeR, XPathConstants.NODESET);
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			if (doc != null) {
				//doc.getDocumentElement().normalize(); //Del or concat text node
				Node nTypeS = doc.getDocumentElement();

				String sql_query="";
				try {
					expr = xpath.compile("properties/sql-query[@t='d']/text()");
					sql_query = (String) expr.evaluate(nTypeS, XPathConstants.STRING);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}

				logger.info("sql_query = " + sql_query);
				/*for(int i=0;i<node_properties.getLength();i++)
				{
				String vn=node_properties.item(i).getAttributes().getNamedItem("n").getNodeValue();
				String val=node_properties.item(i).getTextContent();
				
				//Так как тип узла не передётся в запросе выбираем его отдельно
				String vt="";
				expr = xpath.compile("properties/prop[@n='"+vn+"']");
					exprResult = expr.evaluate(nTypeS, XPathConstants.NODESET);
					nodeList = (NodeList) exprResult;
					if(nodeList.getLength()>0)
					{
						vt=nodeList.item(0).getAttributes().getNamedItem("vt").getNodeValue();
					}
					
					sql_query=Tools.replaceAll(sql_query,"${"+vn+"}",getSQLValue(vt,val));
				} */

				sql_query = Tools.replaceAll(sql_query,"${id}", getSQLValue("string", obj_id)); //string а не i4 так как некоторые таблицы с uuid
				sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id in sql query.

				//logger.info("sql_query = " + sql_query);

				try {
					Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					ResultSet rs = stt.executeQuery(sql_query);
					if (rs != null) {
						try {
							if (rs.next())
								obj_id = rs.getString(1);
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}
						String xmlstring = "<metadata fn=\"3\"><type n=\"" + typename + "\" id=\"" + obj_id + "\"></type></metadata>";

						result=xmlstring;
						//logger.info("xmlstring = " + xmlstring);
					}
					rs.close();
					stt.close();
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
					error=true;
				}

			}

		} else if (fn != null && (fn.equals("4") || fn.equals("11"))) {
			int rowspagecount = 100; //Records per page
			String typename = "";
			String pagepos = "";

			Node nTypeR = null;
			if (doc != null) {
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);
					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					pagepos = "" + nTypeR.getAttributes().getNamedItem("pp").getNodeValue(); //The current page number
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			//Find XML node "type" by name
			if (doc != null) {
				//doc.getDocumentElement().normalize(); //Del or concat text node
				Node nTypeS = doc.getDocumentElement();

				if (nTypeS != null) {
					Node f1 = null, f2 = null;
					//В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного
					NodeList nodeList = null;
					try {
						nodeList = (NodeList) xpath.compile("objects-list/filter").evaluate(nTypeS, XPathConstants.NODESET);
						if (nodeList.getLength() > 0)
							f1 = nodeList.item(0);
						nodeList = (NodeList) xpath.compile("objects-list/filter").evaluate(nTypeR, XPathConstants.NODESET);
						if (nodeList.getLength() > 0)
							f2 = nodeList.item(0);						
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}

					//logger.info("f1=\n" + nodeToString(f1));
					//logger.info("f1=\n" + nodeToString(f2));

					setFilter(f1, f2);//заменить все значения первого фильтра значениями из второго

					//logger.info("f1=\n" + nodeToString(f1));
					//logger.info("f1=\n" + nodeToString(f2));

					String sql_query="";
					try {
						sql_query = (String) xpath.compile("objects-list/sql-query/text()").evaluate(nTypeS, XPathConstants.STRING);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}

					//logger.info("sql_query = " + sql_query);

					Node nextnode = f1.getFirstChild();
					while (nextnode != null) {
						if (nextnode.getNodeName().equals("column")) {
							try {
								String vn = nextnode.getAttributes().getNamedItem("n").getNodeValue();
								/*String size;
								Node n = nextnode.getAttributes().getNamedItem("size");
								if (n != null) {
									size = n.getNodeValue();
								}*/
								String vt = nextnode.getAttributes().getNamedItem("vt").getNodeValue();
								String val = getCharacterDataFromElement((Element) nextnode);

								val = getSQLValue(vt, val);

								sql_query = Tools.replaceAll(sql_query,"${" + vn + "}", val);
							} catch (Exception ex) {
								logger.info(ex.getMessage());
								logger.info("exception = " + ex.getMessage());
							}
						}
						nextnode = nextnode.getNextSibling();
					}
					sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id in sql query.

					//logger.info("sql_query = " + sql_query);

					try {
						Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
						ResultSet rs = stmt.executeQuery(sql_query);
						int pagecount = 0;
						try {
							if (rs.last()) {
								pagecount = rs.getRow();
								rs.beforeFirst();
							}
						} catch (Exception ex) {
							logger.info(ex.getMessage());
							result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
							error=true;
						}
						pagecount = (int) Math.ceil((double) pagecount / (double) rowspagecount);

						//В месте с фильтром может прити и название полей которые нужно выбрать если есть хоть 1 поле то выберать только его
						List<String> columns = new ArrayList<String>();

						try {
							nodeList = (NodeList) xpath.compile("objects-list/column").evaluate(nTypeR, XPathConstants.NODESET);
						} catch (XPathExpressionException ex) {
							logger.info(ex.getMessage());
						}
						if(nodeList!=null)
						{
							for (int i = 0; i < nodeList.getLength(); i++) {
								columns.add(nodeList.item(i).getAttributes().getNamedItem("n").getNodeValue());
							}
						}

						if (columns.size() == 0) //Если нет ни одного столбца заполняем массив из серверного XML
						{
							try {
								nodeList = (NodeList) xpath.compile("objects-list/column").evaluate(nTypeS, XPathConstants.NODESET);
							} catch (XPathExpressionException ex) {
								logger.info(ex.getMessage());
							}
							for (int i = 0; i < nodeList.getLength(); i++) {
								columns.add(nodeList.item(i).getAttributes().getNamedItem("n").getNodeValue());
							}
						}

						//перебираем RS и строим XML только из тех столбцов которые записанны в секци objects-list поля column в не зависимости от их видимости
						String xmlstring = "";
						xmlstring += "<metadata fn=\"" + fn + "\"><type n=\"" + typename + "\" pc=\"" + pagecount + "\" pp=\"" + pagepos + "\">\n";

						int pos = -1;

						// iterate through the java resultset
						try {
							while (rs.next()) {
								pos++;
								if ((Integer.parseInt(pagepos) != -1) && ((pos < (Integer.parseInt(pagepos) * rowspagecount)) || (pos >= Integer.parseInt(pagepos) * rowspagecount + rowspagecount)))
									continue;

								String access = ""; //u = enable update field, d = enable delete field
								try {
									if (rs.getBoolean("_u") == true)
										access += "u";
								} catch (java.sql.SQLException e) {
									access += "u";
								}
								try {
									if (rs.getBoolean("_d") == true)
										access += "d";
								} catch (java.sql.SQLException e) {
									access += "d";
								}

								String id = "";
								try {
									id = rs.getString(nTypeS.getAttributes().getNamedItem("ObjectID").getNodeValue());
								} catch (SQLException e) {
								}

								xmlstring += "	<record id=\"" + id + "\" a=\"" + access + "\">";
								for (int i = 0; i < columns.size(); i++) {
									try {
										String val = rs.getString(columns.get(i));
										if (val == null)
											val = "";
										xmlstring += "<![CDATA[" + val + "]]>";
									} catch (SQLException e) {
									}
								}
								xmlstring += "</record>\n";
							}
						} catch (NumberFormatException | DOMException | SQLException ex) {
							logger.info(ex.getMessage());
						}

						xmlstring += "</type></metadata>\n";

						result=xmlstring;
						//logger.info("xmlstring = " + xmlstring);						
						
						rs.close();
						stmt.close();
						rs=null;
						stmt=null;
						
					} catch (SQLException ex) {
						logger.info(ex.getMessage());
						ex.printStackTrace();
						result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
						error=true;
					}
				}
			}
		} else if (fn != null && fn.equals("5")) {
			String sql_query = "";
			String typename = "";
			String idname = "";

			Node nTypeR = null;
			if (doc != null) {
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);
					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					idname = "" + nTypeR.getAttributes().getNamedItem("id").getNodeValue();
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			if (doc != null) {
				//doc.getDocumentElement().normalize(); //Del or concat text node
				Node nTypeS = doc.getDocumentElement();

				if (nTypeS != null) {
					//Select SQL query to editing record
					sql_query="";
					try {
						sql_query = (String) xpath.compile("properties/sql-query[@t='s']/text()").evaluate(nTypeS, XPathConstants.STRING);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}

					sql_query = Tools.replaceAll(sql_query,"${id}", getSQLValue("string", idname)); //Set current record id into sql query.
					sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id into sql query.

					//logger.info("sql_query = " + sql_query);

					//st = conn.createStatement();

					 
					try {
						Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
						ResultSet rs = stt.executeQuery(sql_query);
						if (rs != null) {
							//Выбираем данные и строим XML для отправки клиенту
							String xmlstring = "";
							xmlstring += "<metadata fn=\"" + fn + "\"><type n=\"" + typename + "\" id=\"" + idname + "\"><properties>\n";
							NodeList nodeList=null;
							try {
								nodeList = (NodeList) xpath.compile("properties/prop").evaluate(nTypeS, XPathConstants.NODESET);
							} catch (XPathExpressionException ex) {
								logger.info(ex.getMessage());
							}
							// iterate through the java resultset
							if(nodeList!=null)
							{
								try {
									while (rs.next()) {
										for (int i = 0; i < nodeList.getLength(); i++) {
											String fName = nodeList.item(i).getAttributes().getNamedItem("n").getNodeValue();
											String val = rs.getString(fName);
											if (val == null)
												val = "";
											xmlstring += "<prop n=\"" + fName + "\"><![CDATA[" + val + "]]></prop>";
										}
									}
								} catch (DOMException | SQLException ex) {
									logger.info(ex.getMessage());
								}
							}
							xmlstring += "</properties></type></metadata>\n";

							result=xmlstring;
							//logger.info("xmlstring = " + xmlstring);
						}
						rs.close();
						stt.close();
						rs=null;
						stt=null;
					} catch (SQLException ex) {
						logger.info(ex.getMessage());
						result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
						error=true;
					}
				}
			}
		} else if (fn != null && fn.equals("6")) //TODO concat width 4 and 11 function
		{
			//String sql_query="";
			String typename = "";
			String[] columns = null;
			String propName = "";

			Node nTypeR = null;
			if (doc != null) {
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);
					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					String columnname;
					columnname = "" + nTypeR.getAttributes().getNamedItem("c").getNodeValue();

					//logger.info("columnname = " + columnname);
					columns = columnname.split(",");

					propName = "" + nTypeR.getAttributes().getNamedItem("pn").getNodeValue(); //Название поля <prop> нигде не используется передаётся обратно в результат
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			//Находим серверный XML узел по имени
			if (doc != null) {
				//doc.getDocumentElement().normalize(); //Del or concat text node
				Node nTypeS = doc.getDocumentElement();

				if (nTypeS != null) {
					Node f1 = null, f2 = null;
					//В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного
					//NodeList nodeList;
					try {
						NodeList nodeList = (NodeList) xpath.compile("objects-list/filter").evaluate(nTypeS, XPathConstants.NODESET);
						if (nodeList.getLength() > 0)
							f1 = nodeList.item(0);
						nodeList = (NodeList) xpath.compile("objects-list/filter").evaluate(nTypeR, XPathConstants.NODESET);
						if (nodeList.getLength() > 0)
							f2 = nodeList.item(0);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}

					//logger.info("Server f1=\n" + nodeToString(f1));
					//logger.info("Request f2=\n" + nodeToString(f2));

					setFilter(f1, f2);//заменить все значения первого фильтра значениями из второго

					//logger.info("Server f1=\n" + nodeToString(f1));
					//logger.info("Request f2=\n" + nodeToString(f2));

					String sql_query="";
					try {
						sql_query = (String) xpath.compile("objects-list/sql-query/text()").evaluate(nTypeS, XPathConstants.STRING);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}

					//logger.info("sql_query = " + sql_query);

					Node nextnode = f1.getFirstChild();
					while (nextnode != null) {
						if (nextnode.getNodeName().equals("column")) {
							try {
								String vn = nextnode.getAttributes().getNamedItem("n").getNodeValue();
								/*String size;
								Node n = nextnode.getAttributes().getNamedItem("size");
								if (n != null) {
									size = n.getNodeValue();
								}*/
								String vt = nextnode.getAttributes().getNamedItem("vt").getNodeValue();
								String val = getCharacterDataFromElement((Element) nextnode);

								val = getSQLValue(vt, val);

								sql_query = Tools.replaceAll(sql_query,"${" + vn + "}", val);
							} catch (Exception ex) {
								logger.info(ex.getMessage());
								//error=true; //throw new Exception(ex);
							}
						}
						nextnode = nextnode.getNextSibling();
					}

					sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id in sql query.

					//logger.info("sql_query = " + sql_query);

					try {
						Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
						ResultSet rs = stt.executeQuery(sql_query);
						if (rs != null) {
							//перебираем RS и строим XML только из тех столбцов которые записанны в секци objects-list поля column в не зависимости от их видимости
							String xmlstring = "";
							xmlstring += "<metadata fn=\"" + fn + "\"><type n=\"" + typename + "\" pn=\"" + propName + "\">\n";

							// iterate through the java resultset
							try {
								while (rs.next()) {
									xmlstring += "	<record id=\"" + rs.getString(nTypeS.getAttributes().getNamedItem("ObjectID").getNodeValue()) + "\">";
									for (int i = 0; i < columns.length; i++) {
										xmlstring += "<![CDATA[" + rs.getString(columns[i]) + "]]>";
									}
									xmlstring += "</record>\n";
								}
							} catch (DOMException | SQLException ex) {
								logger.info(ex.getMessage());
							}
							xmlstring += "</type></metadata>\n";

							result=xmlstring;
							//logger.info("xmlstring = " + xmlstring);
						}
						rs.close();
						stt.close();
						rs=null;
						stt=null;
					} catch (SQLException ex) {
						logger.info(ex.getMessage());
						result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
						error=true;
					}



				} else {
					result="<metadata fn=\"-1\"><![CDATA[Could not find the requested node!]]></metadata>";
					error=true;
				}
			}

		} else if (fn != null && fn.equals("7")) //Login function
		{
			String user_id = "";
			String cmd="";
			String login = "";
			String password = "";
			String hash = "";
			//String captcha = "";
			//For registration new user
			String country_id = "";
			String lastname = "";
			String firstname = "";
			String company = "";
			String position = "";
			String phone = "";
			String email = "";

			try {
				cmd = (String) xpath.compile("//metadata/cmd/text()").evaluate(reqNode, XPathConstants.STRING);
				login = (String) xpath.compile("//metadata/login/text()").evaluate(reqNode, XPathConstants.STRING);
				password = (String) xpath.compile("//metadata/password/text()").evaluate(reqNode, XPathConstants.STRING);
				hash = (String) xpath.compile("//metadata/hash/text()").evaluate(reqNode, XPathConstants.STRING); //Сессия для авто логина если не пустая то сначала пытаемся авторизоваться по ней
				//captcha = (String) xpath.compile("//metadata/captcha/text()").evaluate(reqNode, XPathConstants.STRING);
				//For registration new user
				country_id = (String) xpath.compile("//metadata/country_id/text()").evaluate(reqNode, XPathConstants.STRING);
				lastname = (String) xpath.compile("//metadata/lastname/text()").evaluate(reqNode, XPathConstants.STRING);
				firstname = (String) xpath.compile("//metadata/firstname/text()").evaluate(reqNode, XPathConstants.STRING);
				company = (String) xpath.compile("//metadata/company/text()").evaluate(reqNode, XPathConstants.STRING);
				position = (String) xpath.compile("//metadata/position/text()").evaluate(reqNode, XPathConstants.STRING);
				phone = (String) xpath.compile("//metadata/phone/text()").evaluate(reqNode, XPathConstants.STRING);
				email = (String) xpath.compile("//metadata/email/text()").evaluate(reqNode, XPathConstants.STRING);
			} catch (XPathExpressionException ex) {
				logger.info(ex.getMessage());
			}		
			
			String xmlstring = "";
			if (cmd.equals("0")) //Restore password by email
			{
				boolean find = false;

				try {
					Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					String sql = "select id from main._users where del=false and lower(email)=lower('" + login + "');";
					ResultSet rs = stt.executeQuery(sql);
					if (rs != null) {
						try {
							if (rs.next())
								find = true;
							rs.close();
						} catch (SQLException ex) {
							logger.info(ex.getMessage());		
						}					
					}
					rs.close();
					stt.close();
					rs=null;
					stt=null;
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					xmlstring = "<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
					error=true;
				}


				if (find) {
					String newPass = getRandomString(6);

					boolean mEerror = false;

					String recipient = login;
					String subject = "New password for CCALM from http://www.ccalm.org";
					String content = "Login is: "+ email.toLowerCase()+"\n<br> New password: " + newPass;

					
					String answer = "";
					try {
						EmailUtility.sendEmail(mail_host, mail_port, mail_login, mail_password, recipient, subject, content);
						answer = "New password was sent successfully on \"" + recipient + "\".\nIf there is no email then check the spam folder.";
					} catch (Exception ex) {
						logger.info(ex.getMessage());
						answer = "There were an error: " + ex.getMessage();
						//error=true;
					} finally {
						//request.setAttribute("Message", resultMessage);
						//context.getRequestDispatcher("/Result.jsp").forward(request, response);
					}

					if (!mEerror) {
						try {
							Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
							stt.execute("update main._users set password=md5('" + newPass + "') where email=lower('" + login + "');");
							stt.close();
							stt=null;
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
							xmlstring = "<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
						}
					}

					xmlstring = "<metadata fn=\"7\"><![CDATA[" + answer + "]]></metadata>";
				} else {
					xmlstring = "<metadata fn=\"-1\"><![CDATA[This email address was not registered!]]></metadata>";
				}

			} else if (cmd.equals("1")) //Logout
			{
				String sql_query="select main.p__logout("+user.id+");";
				
				//Отмечаем в базе что пользователь вышел (для электронной очереди если пользователь обрабатывается)
				try {
					Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					ResultSet rs = stt.executeQuery(sql_query);
					rs.close();
					stt.close();
					rs=null;
					stt=null;
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					xmlstring = "<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
					error=true;
				}

				if(!error)
				{
					user.Logout(); //Обнуляем значения
					xmlstring = "<metadata fn=\"7\"><cmd><![CDATA[1]]></cmd></metadata>";
				}

			} else if (cmd.equals("2")) //Check if user not logged.
			{
				if (user.id != null && !user.id.equals("null")) {
					xmlstring = "<metadata fn=\"7\"><cmd><![CDATA[2]]></cmd><![CDATA[1]]></metadata>";
				} else {
					xmlstring = "<metadata fn=\"7\"><cmd><![CDATA[2]]></cmd><![CDATA[0]]></metadata>";
				}

			} else if (cmd.equals("3")) //Login user (Login function from metadata.xml)
			{
				if (login.equals("") && password.equals("")) {
					user_id = (String) user.id;
					if (user_id == null)
						user_id = "null";
				}

				String typename = "_Login";
				//Get XML node "type" from database and parse to DOM
				doc = parseString(getTypeStrNode(conn,typename));

				//Находим серверный XML узел по имени
				if (doc != null) {
					//doc.getDocumentElement().normalize(); //Del or concat text node
					Node nTypeS = doc.getDocumentElement();

					if (nTypeS != null) {
						String sql_query="";
						try {
							sql_query = (String) xpath.compile("objects-list/sql-query/text()").evaluate(nTypeS, XPathConstants.STRING);
						} catch (XPathExpressionException ex) {
							logger.info(ex.getMessage());
						}

						String val;
						val = getSQLValue("i4", user_id);
						sql_query = Tools.replaceAll(sql_query,"${user_id}", val);
						val = getSQLValue("string", login);
						sql_query = Tools.replaceAll(sql_query,"${login}", val);
						val = getSQLValue("string", password);
						sql_query = Tools.replaceAll(sql_query,"${password}", val);
						val = getSQLValue("string", hash);
						sql_query = Tools.replaceAll(sql_query,"${hash}", val);
						val = getSQLValue("string", ""/*request.getSession().getId()*/);
						sql_query = Tools.replaceAll(sql_query,"${sessionid}", val);
						val = getSQLValue("string", ""/*request.getRemoteAddr()*/);
						sql_query = Tools.replaceAll(sql_query,"${ip}", val);

						//logger.info("sql_query = " + sql_query);

						try {
							Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
							ResultSet rs = stt.executeQuery(sql_query);

							if (rs != null) {
								if (rs.next()) {
									user_id = rs.getString("id");
									if(user_id==null) user_id="null";
									user.id=user_id;
									String uName = rs.getString("name");
									user.name=uName;
									String role = rs.getString("role");
									user.role=role;
									user.language_id=rs.getString("language_id");
									String date = rs.getString("date"); //Дата с sql сервера
									String expiration = rs.getString("expiration"); //Дата до которой действует пароль
									String renewal = rs.getString("renewal"); //На сколько дней продлевать действие пароля

									xmlstring = "<metadata fn=\"7\"><cmd><![CDATA[3]]></cmd><![CDATA[1]]><hash><![CDATA[" + hash 
											+ "]]></hash><sesid><![CDATA[]]></sesid><sesname><![CDATA[JSESSIONID]]></sesname><name><![CDATA[" + uName 
											+ "]]></name><role><![CDATA[" + role + "]]></role><date><![CDATA[" + date + "]]></date><expiration><![CDATA[" + expiration
											+ "]]></expiration><renewal><![CDATA[" + renewal + "]]></renewal></metadata>";
								}else
								{
									xmlstring = "<metadata fn=\"-1\"><![CDATA[Error_in_login_or_password]]></metadata>";
								}
							}
							rs.close();
							stt.close();
							rs=null;
							stt=null;
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
							xmlstring = "<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
							error=true;
						}

					}
				}
			} else if (cmd.equals("4")) //Create new user
			{
				xmlstring = "<metadata fn=\"7\"><cmd><![CDATA[4]]></cmd><![CDATA[0]]></metadata>"; //if error

				String newPass = getRandomString(8);
				String sql_query = "select * from main.p__Users_1(4,${country_id},${surname},${name},${company},${position},${phone},${email},${password});";

				String val;
				val = getSQLValue("i4", country_id);
				sql_query = Tools.replaceAll(sql_query,"${country_id}", val);
				val = getSQLValue("string", lastname);
				sql_query = Tools.replaceAll(sql_query,"${surname}", val);
				val = getSQLValue("string", firstname);
				sql_query = Tools.replaceAll(sql_query,"${name}", val);
				val = getSQLValue("string", company);
				sql_query = Tools.replaceAll(sql_query,"${company}", val);
				val = getSQLValue("string", position);
				sql_query = Tools.replaceAll(sql_query,"${position}", val);
				val = getSQLValue("string", phone);
				sql_query = Tools.replaceAll(sql_query,"${phone}", val);
				val = getSQLValue("string", email);
				sql_query = Tools.replaceAll(sql_query,"${email}", val);
				val = getSQLValue("string", newPass);
				sql_query = Tools.replaceAll(sql_query,"${password}", val);

				//logger.info("sql_query = " + sql_query);


				try {
					Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
					ResultSet rs = stt.executeQuery(sql_query);
					if (rs != null) {
						try {
							if (rs.next()) {
								xmlstring = "<metadata fn=\"7\"><cmd><![CDATA[4]]></cmd><![CDATA[1]]></metadata>";

								//Отправляем пароль на Email					
								String recipient = email;
								String subject = "Password for new user on http://www.ccalm.org";
								String content = "Login is: "+ email.toLowerCase()+"\n<br> Password: " + newPass;

								//String answer = "";
								try {
									EmailUtility.sendEmail(mail_host, mail_port, mail_login, mail_password, recipient, subject, content);
									//answer = "New password was sent successfully on \"" + recipient + "\".\nIf there is no email then check the spam folder.";
								} catch (Exception ex) {
									logger.info(ex.getMessage());
									//answer = "There were an error: " + ex.getMessage();
								} finally {
									//request.setAttribute("Message", resultMessage);
									//context.getRequestDispatcher("/Result.jsp").forward(request, response);
								}

							}
						} catch (SQLException ex) {
							logger.info(ex.getMessage());
						}
					}	
					rs.close();
					stt.close();
					rs=null;
					stt=null;
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
					xmlstring = "<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
					error=true;
				}
			}

			result=xmlstring;
			//logger.info("xmlstring = " + xmlstring);

		} else if (fn != null && fn.equals("8")) {
			//Select information about the current user
			String uName = "<br>";

			try {
				Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
				ResultSet rs = stt.executeQuery("select Coalesce(surname,'') || ' ' || Coalesce(name,'') || ' ' || Coalesce(patronymic,'') as name from main._users where id=" + user.id + "");
				if (rs != null) {
					try {
						while (rs.next()) {
							uName = "<i>" + rs.getString("name") + "</i><br>";
						}
					} catch (SQLException ex) {
						logger.info(ex.getMessage());
					}
				}
				rs.close();
				stt.close();
				rs=null;
				stt=null;
			} catch (SQLException ex) {
				logger.info(ex.getMessage());
				result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
				error=true;
			}

			String typename = "";
			//String pagepos="";

			Node nTypeR = null;
			if (doc != null) {				
				Object exprResult=null;
				try {
					expr = xpath.compile("//metadata/type");
					exprResult = expr.evaluate(reqNode, XPathConstants.NODESET);
				} catch (XPathExpressionException ex) {
					logger.info(ex.getMessage());
				}
				NodeList nodeList = (NodeList) exprResult;
				if (nodeList.getLength() > 0) {
					nTypeR = nodeList.item(0);
					typename = "" + nTypeR.getAttributes().getNamedItem("n").getNodeValue();
					//pagepos = "" + nTypeR.getAttributes().getNamedItem("pp").getNodeValue();  //The current page number
				}
			}

			//Get XML node "type" from database and parse to DOM
			doc = parseString(getTypeStrNode(conn,typename));

			//Находим серверный XML узел по имени
			if (doc != null) {
				Node nTypeS = doc.getDocumentElement();

				if (nTypeS != null) {
					Node f1 = null, f2 = null;
					//В переданном запросе может быть не полный фильтр заполняем серверный значениями из переданного
					NodeList nodeList=null;
					try {
						nodeList = (NodeList) xpath.compile("objects-list/filter").evaluate(nTypeS, XPathConstants.NODESET);
						if (nodeList.getLength() > 0)
							f1 = nodeList.item(0);
						nodeList = (NodeList) xpath.compile("objects-list/filter").evaluate(nTypeR, XPathConstants.NODESET);
						if (nodeList.getLength() > 0)
							f2 = nodeList.item(0);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}


					//logger.info("f1=\n" + nodeToString(f1));
					//logger.info("f1=\n" + nodeToString(f2));

					setFilter(f1, f2);//заменить все значения первого фильтра значениями из второго

					//logger.info("f1=\n" + nodeToString(f1));
					//logger.info("f1=\n" + nodeToString(f2));

					//Filter options for display in the header Excel(XLS) document.
					/*
					String filter="<b>"+trt("Filter_options",user)+":</b><br>";
							expr = xpath.compile("objects-list/filter/column");        		
					    	exprResult = expr.evaluate(nTypeR, XPathConstants.NODESET);
					    	nodeList = (NodeList) exprResult;
							for(int i=0;i<nodeList.getLength();i++)
							{
								if(nodeList.item(i).getAttributes().getNamedItem("d").getNodeValue()!="0")
								{
					    			filter+="<i>"+nodeList.item(i).getAttributes().getNamedItem("d").getNodeValue()+": </i>";
					    			filter+=getCharacterDataFromElement((Element)nodeList.item(i));
							filter+="<br>";
								}
							}
							*/

					String sql_query="";
					try {
						sql_query = (String) xpath.compile("objects-list/sql-query/text()").evaluate(nTypeS, XPathConstants.STRING);
					} catch (XPathExpressionException ex) {
						logger.info(ex.getMessage());
					}

					//sql_query=Tools.replaceAll(sql_query,"${id}","null");
					//logger.info("sql_query1 = " + sql_query);

					Node nextnode = f1.getFirstChild();
					while (nextnode != null) {
						if (nextnode.getNodeName().equals("column")) {
							try {
								String vn = nextnode.getAttributes().getNamedItem("n").getNodeValue();
								/*String size;
								Node n = nextnode.getAttributes().getNamedItem("size");
								if (n != null) {
									size = n.getNodeValue();
								}*/
								String vt = nextnode.getAttributes().getNamedItem("vt").getNodeValue();
								String val = getCharacterDataFromElement((Element) nextnode);

								val = getSQLValue(vt, val);

								sql_query = Tools.replaceAll(sql_query,"${" + vn + "}", val);
							} catch (Exception ex) {
								logger.info(ex.getMessage());
							}
						}
						nextnode = nextnode.getNextSibling();
					}
					sql_query = Tools.replaceAll(sql_query,"${_user_id}", (String) user.id); //Set current user id in sql query.

					//logger.info("sql_query2 = " + sql_query);


					try {
						Statement stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
						ResultSet rs = stt.executeQuery(sql_query);
						if (rs != null) {
							//Create Excel file and write result set
							Writer writer = null;
							Random rand = new Random();
							String tmpName = "file_" + rand.nextInt(1000) + ".xls"; //TODO Not safety, the file names can match.

							try {								
								String tmpPath = data_dir + "temp" + File.separator;
								File file = new File(tmpPath);
								if (!file.exists()) {
									file.mkdirs();
								}

								writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tmpPath + tmpName), "utf-8"));

								writer.write("<html>\n");
								writer.write("	<head>\n");
								writer.write("		<title>" + nTypeS.getAttributes().getNamedItem("d").getNodeValue() + "</title>\n");
								writer.write("		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
								writer.write("<style>td {mso-number-format: \"\\@\";}</style>");
								writer.write("	</head>\n");
								writer.write("	<body>\n");

								writer.write("<b>" + trt(conn,"Time_and_date_of_generation",user) + ": </b><i>" + (new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date())) + "</i><br>");
								writer.write("<b>" + trt(conn,"Creator",user) + ": </b>" + uName);

								//writer.write(filter);

								xPathfactory = XPathFactory.newInstance();
								xpath = xPathfactory.newXPath();
								try {
									expr = xpath.compile("objects-list/@d");
		
									writer.write("		<table border=\"1\" cellspacing=\"0\">\n");
									writer.write("			<caption><b>" + getText(conn,"" + expr.evaluate(nTypeS, XPathConstants.STRING),user) + "</b></caption>\n");
									writer.write("			<thead>\n");
									writer.write("				<tr>");
		
									expr = xpath.compile("objects-list/column");
									Object exprResult = expr.evaluate(nTypeS, XPathConstants.NODESET);
									nodeList = (NodeList) exprResult;
									for (int i = 0; i < nodeList.getLength(); i++) {
										writer.write("<td bgcolor=\"#d1d1d1\" width=\"" + nodeList.item(i).getAttributes().getNamedItem("width").getNodeValue() + "px\"><b>" + getText(conn,nodeList.item(i).getAttributes().getNamedItem("d").getNodeValue(),user)
												+ "</b></td>");
									}
									writer.write("				</tr>\n");
									writer.write("			</thead>\n");
									writer.write("			<tbody>\n");
		
									while (rs.next()) {
										writer.write("				<tr>");
										for (int i = 0; i < nodeList.getLength(); i++) {
											String val = rs.getString(nodeList.item(i).getAttributes().getNamedItem("n").getNodeValue());
											if (val == null)
												val = "";
											writer.write("<td>" + val + "</td>");
										}
										writer.write("</tr>\n");
									}
									writer.write("			</tbody>\n");
									writer.write("		</table>\n");
									writer.write("	</body>\n");
									writer.write("</html>\n");
								} catch (XPathExpressionException | DOMException | SQLException ex) {
									logger.info(ex.getMessage());
								}
							} catch (IOException ex) {
								logger.info(ex.getMessage());
								result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "]]></metadata>";
								error=true;
							} finally {
								try {
									writer.close();
								} catch (Exception ex) {
								}
							}
							//Отправляем название файла на сервер
							result="<metadata fn=\"8\"><file><![CDATA[" + tmpName + "]]></file></metadata>";
						}
						rs.close();
						stt.close();
						rs=null;
						stt=null;
					} catch (SQLException ex) {
						logger.info(ex.getMessage());
						result="<metadata fn=\"-1\"><![CDATA[Error: " + ex.getMessage() + "\n\nSQL query: " + sql_query + "]]></metadata>";
						error=true;
					}
				}
			}

		} else if (fn != null && fn.equals("9")) {
			// https://www.tutorialspoint.com/jsp/jsp_file_uploading.htm
/*
			File file;
			int maxFileSize = 5000 * 1024;
			int maxMemSize = 5000 * 1024;
			String filePath = context.getInitParameter("file-upload");

			// Verify the content type
			String contentType = request.getContentType();

			if (contentType != null && contentType.indexOf("multipart/form-data") >= 0) {
				DiskFileItemFactory factory = new DiskFileItemFactory();
				//factory.setSizeThreshold(maxMemSize); // maximum size that will be stored in memory
				//factory.setRepository(new File("O:\\temp\\upload")); // Location to save data that is larger than maxMemSize.

				// Create a new file upload handler
				ServletFileUpload upload = new ServletFileUpload(factory);

				// maximum file size to be uploaded.
				upload.setSizeMax(maxFileSize);

				try {
					// Parse the request to get file items.
					List<FileItem> fileItems = upload.parseRequest(request);

					// Process the uploaded file items
					Iterator<FileItem> i = fileItems.iterator();

					while (i.hasNext()) {
						FileItem fi = (FileItem) i.next();
						if (!fi.isFormField()) {
							// Get the uploaded file parameters
							String fieldName = fi.getFieldName();
							String fileName = fi.getName();
							boolean isInMemory = fi.isInMemory();
							long sizeInBytes = fi.getSize();

							// Write the file
							file = new File(filePath + fileName);
							fi.write(file);

							//Calc CRC32
							long crc32=0;
							FileInputStream fin = new FileInputStream(filePath + fileName);
						    Checksum sum_control = new CRC32();
						    for (int b = fin.read(); b != -1; b = fin.read()) {
								sum_control.update(b);
						    }
						    crc32 = sum_control.getValue();
						    fin.close();
						    
							//To be rename file, add CRC32 in begin.
							File srcFile  = new File(filePath + fileName);
				            File destFile = new File(filePath + Long.toHexString(crc32) +"_"+ fileName);
							FileUtils.copyFile(srcFile, destFile);
							FileUtils.forceDelete(srcFile);

							logger.info("Uploaded Filename: " + Long.toHexString(crc32) +"_"+ fileName);
							response.getWriter().append("ok=" + Long.toHexString(crc32) +"_"+ fileName + "\n");
						}
					}

				} catch (Exception ex) {
					logger.info(ex);
				}
			}

			//This code put into iframe
			response.setContentType("text/html");

			response.getWriter().append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
			response.getWriter().append("<html>");
			response.getWriter().append("	<head>");
			response.getWriter().append("		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>");
			response.getWriter().append("	</head>");
			response.getWriter().append("	<body>");
			response.getWriter().append("		<form name=\"form\" enctype=\"multipart/form-data\" action=\"?fn=9\" method=\"post\">");
			response.getWriter().append("			<input type=\"hidden\" name=\"state\" value=\"\"/>");
			response.getWriter().append("			<input type=\"file\" name=\"file\"><br/>");
			response.getWriter().append("			<input type=\"submit\" value=\"Send File\">");
			response.getWriter().append("			<input type=\"reset\"  value=\"Reset\">");
			response.getWriter().append("		</form>");
			response.getWriter().append("	</body>");
			response.getWriter().append("</html>");

			//Отчищяем временные файлы которые больше суток на сервере
			//deleteTempFiles($dir);
*/

		} else {
			result="<metadata fn=\"-1\"><![CDATA[Unknown function \"" + fn + "\" !]]></metadata>";
			error=true;
		}
		
		try {
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		//return body content
    	return result;
    }
 
	@Override
	public void setServletContext(ServletContext context) {
		this.context=context;
	}

	/**
	 * Example request: http://localhost:8080/CCALM/download?t=FrmLocust&f=image_name1&i=1298
	 */
	@RequestMapping(value = "/download", method = RequestMethod.GET,produces = "application/octet-stream")
	@ResponseBody
	public FileSystemResource home(HttpServletResponse response,@ModelAttribute User user,@RequestParam(required=false,name="t") String typename,@RequestParam(required=false,name="f") String field,@RequestParam(required=false,name="i") String id) {

		String metadata_file = "";
		String db_url = "";
		String db_login = "";
		String db_password = "";
		//String data_dir = "";
		//Load DB configuration from "config.xml"
		try {
			//String fullPath = context.getRealPath("/WEB-INF/config.xml");
			//File fXmlFile = new File(fullPath);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			//Document doc = dBuilder.parse(fXmlFile);
			Document doc = dBuilder.parse(new ClassPathResource("config.xml").getInputStream());
			Element nMain = doc.getDocumentElement();
			NodeList nl = nMain.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				if (nl.item(i).getNodeName().equals("db-url"))
					db_url = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("db-login"))
					db_login = nl.item(i).getTextContent();
				if (nl.item(i).getNodeName().equals("db-password"))
					db_password = nl.item(i).getTextContent();

				if (nl.item(i).getNodeName().equals("metadata"))
					metadata_file = nl.item(i).getTextContent();
				
				//if (nl.item(i).getNodeName().equals("data-dir"))
				//	data_dir = nl.item(i).getTextContent();
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
		}

    	
		Connection conn = null;
		try {
			Class.forName("org.postgresql.Driver");
			conn = DriverManager.getConnection(db_url, db_login, db_password);
			if (conn != null) {
				logger.info("Connect is OK!");
			} else {
				logger.info("An error occurred while connecting to the database!");
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
		}
		Statement stt=null;
		try {
			stt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
		} catch (SQLException ex) {
			logger.info(ex.getMessage());
		}

		//Send the binary data to the client as a file (no resume).
		//String typename = request.getParameter("t"); //Type from metadata.xml
		//String field = request.getParameter("f"); //field name
		//String id = request.getParameter("i"); //field id
		String path="";
		String filename="";
		File file=null;

		//Parse main XML
		Document doc = null;
		try {
			File inputFile = new File(context.getRealPath("/")+"resources"+File.separator+metadata_file);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			doc = dBuilder.parse(inputFile);
		} catch (Exception ex) {
			logger.info(ex.getMessage());
		}

		if (doc != null) {
			doc.getDocumentElement().normalize(); //Del or concat text node
			//response.getWriter().append("Root element: " + doc.getDocumentElement().getNodeName()+" !<br>");

			javax.xml.xpath.XPathFactory xPathfactory = XPathFactory.newInstance();
			XPath xpath = xPathfactory.newXPath();
			XPathExpression expr=null;
			
			Object exprResult=null;
			try {
				expr = xpath.compile("//metadata/type[@n='" + typename + "']");
				exprResult = expr.evaluate(doc, XPathConstants.NODESET);
			} catch (XPathExpressionException ex) {
				logger.info(ex.getMessage());
			}
			NodeList nodeList = (NodeList) exprResult;

			Node nTypeS = null;
			if (nodeList.getLength() > 0)
				nTypeS = nodeList.item(0);

			try {
				expr = xpath.compile("properties/prop[@n='"+field+"']/@path");
				path = (String) expr.evaluate(nTypeS, XPathConstants.STRING);
			} catch (XPathExpressionException ex) {
				logger.info(ex.getMessage());
			}			
		}

		if(path!=null && !path.equals(""))
		{
			ResultSet rs = null;
			try {
				String sql="SELECT "+field+" as name FROM main."+typename+" WHERE id="+String.valueOf(id);
				rs = stt.executeQuery(sql);
			} catch (SQLException ex) {
				logger.info(ex.getMessage());
			}
			if (rs != null) {
				try {
					if (rs.next())
						filename = rs.getString(1);
					rs.close();
				} catch (SQLException ex) {
					logger.info(ex.getMessage());
				}
			}
			if(!filename.equals(""))
			{
				file = new File(path+File.separator+filename);
			}
		}

		if(conn!=null){try{conn.close();}catch(SQLException ex){}}

		if(file!=null) {
			response.setContentType("application/octet-stream");  
		    response.setHeader("Content-Disposition", "attachment; filename="+afterFirst(filename,"_"));
		    response.setHeader("Cache-Control", "no-cache");
			return new FileSystemResource(file);
		}else {
			response.setContentType("text/html");  
			return null;
		}
	}


	@RequestMapping(value = "/upload", method = { RequestMethod.GET, RequestMethod.POST })
	@ResponseBody
	public String uploadFile(HttpServletResponse response,@RequestParam(required=false,name="file") MultipartFile file) {
		
		String result="";
		String data_dir="";
	

		try {
			//String fullPath = context.getRealPath("/WEB-INF/config.xml");
			//File fXmlFile = new File(fullPath);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			//Document doc = dBuilder.parse(fXmlFile);
			Document doc = dBuilder.parse(new ClassPathResource("config.xml").getInputStream());
			Element nMain = doc.getDocumentElement();
			NodeList nl = nMain.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				if (nl.item(i).getNodeName().equals("data-dir"))
					data_dir = nl.item(i).getTextContent();
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
		}

		
		String fileName = "";
 
		if (file!=null && !file.isEmpty()) {
			try {
				
				byte[] bytes = file.getBytes();
				fileName = file.getOriginalFilename();
 
				File dir = new File(data_dir);
				if (!dir.exists()) dir.mkdirs();

				BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(data_dir + fileName)));
				stream.write(bytes);
				stream.flush();
				stream.close(); 

				//Calc CRC32
				long crc32=0;
				FileInputStream fin = new FileInputStream(data_dir + fileName);
			    Checksum sum_control = new CRC32();
			    for (int b = fin.read(); b != -1; b = fin.read()) {
					sum_control.update(b);
			    }
			    crc32 = sum_control.getValue();
			    fin.close();
			    
				//To be rename file, add CRC32 in begin.
				File srcFile  = new File(data_dir + fileName);
	            File destFile = new File(data_dir + Long.toHexString(crc32) +"_"+ fileName);
				FileUtils.copyFile(srcFile, destFile);
				FileUtils.forceDelete(srcFile);

				//logger.info("Uploaded Filename: " + Long.toHexString(crc32) +"_"+ fileName);
				result+="ok=" + Long.toHexString(crc32) +"_"+ fileName + "\n";

				} catch (Exception ex) {
					logger.info(ex.getMessage());
				}
		}

		//This code put into iframe
		response.setContentType("text/html");

		result+="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
		result+="<html>";
		result+="	<head>";
		result+="		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>";
		result+="	</head>";
		result+="	<body>";
		result+="		<form name=\"form\" enctype=\"multipart/form-data\" action=\"upload\" method=\"post\">";
		result+="			<input type=\"hidden\" name=\"state\" value=\"\"/>";
		result+="			<input type=\"file\" name=\"file\"><br/>";
		result+="			<input type=\"submit\" value=\"Send File\">";
		result+="			<input type=\"reset\"  value=\"Reset\">";
		result+="		</form>";
		result+="	</body>";
		result+="</html>";

		//deleteTempFiles($dir);

		return result;
	}

	//Send generated report to the client for downloading
    @RequestMapping(value = "/reports",method = RequestMethod.GET, produces = "application/octet-stream")
    @ResponseBody
    public FileSystemResource sendReport(HttpServletResponse response,@RequestParam(required=true,name="file") String fileName) {
		String data_dir = "";
		//Load DB configuration from "config.xml"
		try {
			//String fullPath = context.getRealPath("/WEB-INF/config.xml");
			//File fXmlFile = new File(fullPath);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			//Document doc = dBuilder.parse(fXmlFile);
			Document doc = dBuilder.parse(new ClassPathResource("config.xml").getInputStream());
			Element nMain = doc.getDocumentElement();
			NodeList nl = nMain.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				if (nl.item(i).getNodeName().equals("data-dir"))
					data_dir = nl.item(i).getTextContent();
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
		}
		

        File file = new File(data_dir + "temp" + File.separator + fileName);
        if(file.exists())
        {
        	//logger.info("Send report: " + fileName);

			//response.setContentType("application/octet-stream"); //Commented because it is specified in the function declaration.
			response.setHeader("Content-Disposition","attachment; filename="+fileName);
			response.setContentLength((int) file.length());
	        return new FileSystemResource(file);
        }else
        {
        	logger.info("File not found: " + fileName);
        	return null;
        }
    }

	String getSQLValue(String t, String v) {
		//if($t=='object' && (strtoupper($v)!='NULL' && gettype($v)=='string')) $t='string'; //Если id шники uuid

		if (t.equals("object") || t.equals("uid")) {
			if (v.equals(""))
				v = "NULL";
		} else if (t.equals("i4") || t.equals("integer")) {
			if (v.equals(""))
				v = "NULL";
		} else if (t.equals("f8")) {
			if (v.equals(""))
				v = "NULL";
			v = Tools.replaceAll(v,",", "."); //The decimal part: point.
		} else if (t.equals("f4")) {
			if (v.equals(""))
				v = "NULL";
			v = Tools.replaceAll(v,",", "."); //The decimal part: point.
		} else if (t.equals("b")) {
			if (v.equals(""))
				v = "NULL";
			else if (v.equals("1"))
				v = "true";
			else if (v.equals("0"))
				v = "false";
		} else if (t.equals("string") || t.equals("text") || t.equals("dateTime") || t.equals("date")) {
			if (v.equals("")) {
				v = "NULL";
			} else {
				v = Tools.replaceAll(v,"'", "''");
				v = "'" + v + "'";
			}
		} else {
			v = "'" + v + "'";
		}
		return v;
	}
	
	private String nodeToString(Node node) {
		StringWriter sw = new StringWriter();
		try {
			Transformer t = TransformerFactory.newInstance().newTransformer();
			t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			t.transform(new DOMSource(node), new StreamResult(sw));
		} catch (TransformerException ex) {
			System.out.println(ex.getMessage());
			System.out.println("nodeToString Transformer Exception");
		}
		return sw.toString();
	}

	//Replace all the values of the first filter values from the second
	public void setFilter(Node n1, Node n2) {
		if (n1 == null || n2 == null)
			return;

		XPathFactory xPathfactory = XPathFactory.newInstance();
		XPath xpath = xPathfactory.newXPath();

		Node nc1 = n1.getFirstChild();
		while (nc1 != null) {
			if (nc1.getNodeName().equals("column")) {
				try {
					String path = "column[@n='" + nc1.getAttributes().getNamedItem("n").getNodeValue() + "']";
					XPathExpression expr = xpath.compile(path);
					NodeList nodeList = (NodeList) expr.evaluate(n2, XPathConstants.NODESET);
					if (nodeList.getLength() > 0) {
						Node nc2 = nodeList.item(0);

						setCharacterDataToElement((Element) nc1, getCharacterDataFromElement((Element) nc2));

						//getCdata($nc1)->nodeValue=getCdata($nc2)->nodeValue;	
					}

				} catch (Exception ex) {
					System.out.println(ex.getMessage());
					//String message = "XML parsing error!";
					//return;
				}
			}
			nc1 = nc1.getNextSibling();
		}
	}

	public static String getCharacterDataFromElement(Element e) {
		Node child = e.getFirstChild();
		if (child instanceof CharacterData) {
			CharacterData cd = (CharacterData) child;
			return cd.getData().trim();
		}
		return "";
	}

	public void setCharacterDataToElement(Element e, String data) {
		Node child = e.getFirstChild();
		if (child instanceof CharacterData) {
			CharacterData cd = (CharacterData) child;
			cd.setData(data);
		} else //Create new CDATA node
		{
			Document doc = e.getOwnerDocument();
			e.appendChild(doc.createCDATASection(data));
		}
	}
	
	public static String getRandomString(int length) {
		final String characters = "abcdefghijklmnopqrstuvwxyz1234567890";
		StringBuilder result = new StringBuilder();
		while (length > 0) {
			Random rand = new Random();
			result.append(characters.charAt(rand.nextInt(characters.length())));
			length--;
		}
		return result.toString();
	}

	//Перевести слово по идентификатору из базы
	public String trt(Connection conn,String key,User user)
	{
		String result="";
		ResultSet rs=null;
		Statement st = null;
		try {
			st = conn.createStatement();
			String sql = "select case when '"+user.language_id+"'='666' then t.translation||'''\"' alse t.translation end as translation from main._translations t where t.identifier='"+key+"' and (t.language_id='"+user.language_id+"' or ('"+user.language_id+"'='666' and t.language_id=1));";
			rs = st.executeQuery(sql);
			if(rs != null) {
				if (rs.next()) {
					result = rs.getString(1);
				}
			}
		} catch( SQLException ex )
		{
			logger.info(ex.getMessage());
		}finally{
			if(st!=null) try{st.close();}catch(SQLException ex) {}
			if(rs!=null) try{rs.close();}catch(SQLException ex) {}
		}

		if(result.equals(""))
		{
			result = Tools.replaceAll(key,"_", " ");
		}
		return result;
	}

	//Translate text by patterns
	public String getText(Connection conn,String text,User user) {
		int pos1 = 0;
		while (true) {
			pos1 = text.indexOf("trt('", pos1);
			if (pos1 == -1)
				break;
			int pos2 = text.indexOf("')", pos1);
			if (pos2 == -1)
				break;

			text = text.substring(0, pos1) + trt(conn,text.substring(pos1 + 5, pos2),user) + text.substring(pos2 + 2);
		}
		return text;
	}
	
	public static String afterFirst(String str, String ch)
	{
		int i=str.indexOf(ch);
		if(i!=-1)
		{
			return str.substring(i+ch.length());
		}
		return "";
    }

	//Получить узел метаданных из базы данных
	public String getTypeStrNode(Connection conn,String typeName)
	{
		String result="";
		String sql="select xml from main._metadata where name='"+typeName+"';";
		try {
    		Statement st = conn.createStatement();
			ResultSet rs=null;
			try {  
				rs = st.executeQuery(sql);
			} catch( SQLException ex ) {
				ex.printStackTrace();
			}
			try {
	    		if(rs!=null)
	    		{
	    			if(rs.next())
	    			{
	    				result=rs.getString(1);
	    			}
					rs.close();
	    		}
				st.close();
			} catch (SQLException ex) {
				ex.printStackTrace();
			}
		} catch (SQLException ex) {
			ex.printStackTrace();
		}
		return result;
	}

	//Пропарсить сткоку в DOM
	public Document parseString(String xml)
	{
		Document doc=null;
		try {
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			doc = dBuilder.parse(new InputSource(new StringReader(xml)));
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return doc;
	}
	
}