import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.adeptia.indigo.logging.Logger;
import com.adeptia.indigo.security.AuthUtil;
import com.adeptia.indigo.services.ServiceException;
import com.adeptia.indigo.services.transform.support.AbstractTransformer;
import com.adeptia.indigo.services.transport.connector.DatabaseConnectionInfo;
import com.adeptia.indigo.storage.Criteria;
import com.adeptia.indigo.storage.EntityManager;
import com.adeptia.indigo.storage.EntityManagerFactory;
import com.adeptia.indigo.utils.JdbcUtils;


Connection connection = null;
PreparedStatement psStmt = null;
NodeList childnodes = null;
Node firstParrent = null;
Document doc = null;
StringBuffer tempXml = null;
String xmlData = null;
String databaseInfoName = "Connect_Analytics_Prod_RO";
String schemaName = "intel";
String tableName = "srd_reporting_current";
String[] jsonColumnName = {"srddata"};
String[] uuidColumnName = {"id","parentid"};
List jsonColumnIndices = new ArrayList();
List uuidColumnIndices = new ArrayList();
String insertQuery = "";
String databasetype = "";
String quote = "\"";
int columnCount = 0;
int totalRecordCount = 0;
Logger log = service.getLogger();
InputStream inputStream = null;
try {
	inputStream = service.getSourceStream();
	BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
	tempXml = new StringBuffer();
	String lineData = null;
	while ((lineData = br.readLine()) != null) {
		tempXml.append(lineData);
	}
	xmlData = tempXml.toString();
	if (inputStream != null)
		inputStream.close();
} catch (IOException e) {
	try {
		inputStream.close();
	} catch (Exception ef) {
		ef.printStackTrace();
	}

	log.error("Error in reading xml stream :: " + e.getMessage(), e);
	throw e;
}

try {
	DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
	DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
	InputSource is = new InputSource();
	is.setCharacterStream(new StringReader(xmlData));
	doc = documentBuilder.parse(is);
	totalRecordCount = doc.getDocumentElement().getChildNodes().getLength();
} catch (ParserConfigurationException e) {
	log.error("Error in xml parsing:: " + e.getMessage(), e);
	throw e;
} catch (SAXException e) {
	log.error("Error in xml parsing:: " + e.getMessage(), e);
	throw e;
} catch (Exception e) {
	log.error(e);
	throw e;
}

try {
	DatabaseConnectionInfo databaseConnectionInfo = null;
	EntityManager entityManager = EntityManagerFactory.getEntityManager(DatabaseConnectionInfo.class,
			AuthUtil.getAdminSubject());
	Criteria criteria = new Criteria("p.entityName=\"" + databaseInfoName + "\"");

	Iterator it = entityManager.retrieve(criteria);
	if (it != null) {
		if (it.hasNext()) {
			databaseConnectionInfo = (DatabaseConnectionInfo) it.next();
		} else {
			throw new ServiceException("Connection information not available");
		}
	}
	connection = JdbcUtils.getConnection(databaseConnectionInfo, AuthUtil.getAdminSubject());
} catch (Exception e) {
	log.error("Error in getting database connection :: " + e.getMessage(), e);
}
try {
	DatabaseMetaData db = connection.getMetaData();
	databasetype = db.getDatabaseProductName();
} catch (SQLException e1) {
	log.error(e1);
}
quote = databasetype.equalsIgnoreCase("MySQL")?"`":quote;
if (totalRecordCount > 0) {
	try {
		List dataToInsert = new ArrayList();
		firstParrent = doc.getDocumentElement().getElementsByTagName(tableName).item(0);
		childnodes = firstParrent.getChildNodes();
		insertQuery = "INSERT INTO " + schemaName +"."+ tableName + "(";
		Node node = null;
		Element childElement = null;
		List jsonColumnList = Arrays.asList(jsonColumnName);
		List uuidColumnList = Arrays.asList(uuidColumnName);
		for (int i = 0; i < childnodes.getLength(); i++) {
			node = childnodes.item(i);
			if (node instanceof Element) {
				childElement = (Element) node;
				insertQuery = insertQuery + quote + childElement.getNodeName() + quote + ",";
				if (jsonColumnList .contains(childElement.getNodeName())) {
					jsonColumnIndices.add(columnCount);
				} else if(uuidColumnList .contains(childElement.getNodeName())) {
					uuidColumnIndices.add(columnCount);
				}
				dataToInsert.add(childElement.getTextContent());
				columnCount++;
			}
		}
		insertQuery = insertQuery.substring(0, insertQuery.lastIndexOf(",")) + ")";
		insertQuery = insertQuery + " VALUES(";
		for (int i = 0; i < columnCount; i++) {
			if (jsonColumnIndices.contains(i)) {
				insertQuery = insertQuery + "? ::jsonb,";
			} else {
				insertQuery = insertQuery + "?,";
			}
		}
		insertQuery = insertQuery.substring(0, insertQuery.lastIndexOf(",")) + ")";
		psStmt = connection.prepareStatement(insertQuery);
		UUID uuid = null;
		String data = null;
		for (int i=0; i<dataToInsert.size(); i++) {
			data = dataToInsert.get(i);
			if(uuidColumnIndices.contains(i)) {
				uuid = data!=null && !data.isEmpty() && !"null".equals(data)?UUID.fromString(data): UUID.randomUUID();
				psStmt.setObject(i+1, uuid);
			}else {
				psStmt.setString(i+1, data);
			}
		}
		psStmt.execute();
	} catch (Exception e) {
		log.error("Error in decoded stream :: " + e.getMessage(), e);
		throw e;
	} finally {
		try {
			if (psStmt != null)
				psStmt.close();
			if (connection != null)
				connection.close();
		} catch (SQLException e) {
			log.error("Error in closing the database object :: " + e.getMessage(), e);
		}
	}
} else {
	try {
		if (connection != null)
			connection.close();
	} catch (SQLException e) {
		log.error("Error in closing the database object :: " + e.getMessage(), e);
	}

}
