All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prerna.reactor.export.ExportToExcelReactor Maven / Gradle / Ivy

The newest version!
package prerna.reactor.export;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFLineProperties;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.BarDirection;
import org.apache.poi.xddf.usermodel.chart.BarGrouping;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
import org.apache.poi.xddf.usermodel.chart.XDDFAreaChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFRadarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFScatterChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.json.JSONArray;
import org.json.JSONObject;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTScatterChart;

import prerna.algorithm.api.SemossDataType;
import prerna.auth.User;
import prerna.auth.utils.AbstractSecurityUtils;
import prerna.auth.utils.SecurityQueryUtils;
import prerna.date.SemossDate;
import prerna.engine.api.IHeadersDataRow;
import prerna.om.ColorByValueRule;
import prerna.om.InsightFile;
import prerna.om.InsightPanel;
import prerna.om.InsightSheet;
import prerna.om.ThreadStore;
import prerna.poi.main.helper.excel.ExcelUtility;
import prerna.query.querystruct.SelectQueryStruct;
import prerna.query.querystruct.selectors.IQuerySelector;
import prerna.query.querystruct.selectors.IQuerySelector.SELECTOR_TYPE;
import prerna.reactor.AbstractReactor;
import prerna.sablecc2.om.GenRowStruct;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.PixelOperationType;
import prerna.sablecc2.om.ReactorKeysEnum;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.sablecc2.om.task.ConstantDataTask;
import prerna.sablecc2.om.task.ITask;
import prerna.sablecc2.om.task.options.TaskOptions;
import prerna.util.ChromeDriverUtility;
import prerna.util.Constants;
import prerna.util.DIHelper;
import prerna.util.Utility;
import prerna.util.insight.InsightUtility;

public class ExportToExcelReactor extends TableToXLSXReactor {

	private static final String CLASS_NAME = ExportToExcelReactor.class.getName();

	private static final String GRID_ON_X = "tools.shared.editGrid.x";
	private static final String GRID_ON_Y = "tools.shared.editGrid.y";
	private static final String DISPLAY_VALUES = "tools.shared.displayValues";
	private static final String SHOW_Y_AXIS_TITLE = "tools.shared.editYAxis.title.show";
	private static final String SHOW_X_AXIS_TITLE = "tools.shared.editXAxis.title.show";
	private static final String Y_AXIS_TITLE_NAME = "tools.shared.editYAxis.title.name";
	private static final String X_AXIS_TITLE_NAME = "tools.shared.editXAxis.title.name";
	private static final String COLOR_NAME = "tools.shared.colorName";
	private static final String CUSTOM_COLOR_ARRAY = "tools.shared.customColors";
	private static final String COLOR_ARRAY = "tools.shared.color";
	private static final String CHART_TITLE = "tools.shared.chartTitle.text";
	
	// for exporting grid
	private static final String GRIDSPANROWS = "tools.shared.gridSpanRows";
	private static final String TABLE_STYLE = "table-layout: fixed;border-collapse: collapse; border: 1px solid #d9d9d9; font-family: Arial, Helvetica, sans-serif; width: 100%; max-width: 600px;";
	private static final String THEAD_STYLE = "background: #f5f5f5; color: #5c5c5c;";
	private static final String TH_STYLE = "border: 1px solid #d9d9d9; padding: 8px;width: 200px; background-color: #00A8C1;color: #FFFFFF;font-size: .875em;";
	private static final String TD_STYLE = "border: 1px solid #d9d9d9; padding: 8px;font-size: .875em;";

	
	protected String fileLocation = null;
	Map > orderOfPanelsMap = null;
	
	protected Logger logger;

	Object driver = null;
	private Map> chartPanelLayout = new HashMap<>();
	int height = 10;
	int width = 10;
	
	ChromeDriverUtility util = null;
	
	// sheet alias
	Map sheetAlias = new HashMap<>();

	public ExportToExcelReactor() {
		this.keysToGet = new String[] { ReactorKeysEnum.FILE_NAME.getKey(), ReactorKeysEnum.FILE_PATH.getKey(),
				ReactorKeysEnum.LIMIT.getKey(), ReactorKeysEnum.PASSWORD.getKey(), ReactorKeysEnum.HEIGHT.getKey(), 
				ReactorKeysEnum.WIDTH.getKey(), 
				ReactorKeysEnum.HEADERS.getKey(), 
				ReactorKeysEnum.ROW_GUTTER.getKey(),
				ReactorKeysEnum.COLUMN_GUTTER.getKey(),
				ReactorKeysEnum.TABLE_HEADER.getKey(),
				ReactorKeysEnum.TABLE_FOOTER.getKey(),
				ReactorKeysEnum.MERGE_CELLS.getKey(), ReactorKeysEnum.EXPORT_TEMPLATE.getKey(),
				ReactorKeysEnum.PANEL_ORDER_IDS.getKey(),
				ReactorKeysEnum.EXPORT_AUDIT.getKey(),
				ReactorKeysEnum.PLACE_HOLDER_DATA.getKey(),
				ReactorKeysEnum.PROJECT.getKey()
			};
		this.keyRequired = new int[] {0,0,0,0,0,0,0,0,0,0,0,0,0};
		this.keyMulti = new int[] {0,0,0,0,0,0,1,0,0,0,0,0,0};
	}
	
	@Override
	public NounMetadata execute() {
		organizeKeys();
		User user = this.insight.getUser();
		// throw error is user doesn't have rights to export data
		if(AbstractSecurityUtils.adminSetExporter() && !SecurityQueryUtils.userIsExporter(user)) {
			AbstractReactor.throwUserNotExporterError();
		}
		// get the map also
		getMap(insight.getInsightId());
		processPayload();
		this.logger = getLogger(CLASS_NAME);

		String downloadKey = UUID.randomUUID().toString();
		InsightFile insightFile = new InsightFile();
		insightFile.setFileKey(downloadKey);
		
		// get a random file name
		String prefixName =  Utility.normalizePath(exportMap.get("FILE_NAME") + ""); 
		String exportName = AbstractExportTxtReactor.getExportFileName(user, prefixName, "xlsx");
		// grab file path to write the file
		String fileLocation =  Utility.normalizePath(this.keyValue.get(ReactorKeysEnum.FILE_PATH.getKey()));
		
		boolean exportAudit = false;
		// check if the export audit has been selected for export
		if (keyValue.containsKey(ReactorKeysEnum.EXPORT_AUDIT.getKey())) {
			String auditParam = (String) keyValue.get(ReactorKeysEnum.EXPORT_AUDIT.getKey());
			exportAudit = auditParam.equalsIgnoreCase("yes") || auditParam.equalsIgnoreCase("true");
		}
		
		// if the file location is not defined generate a random path and set
		// location so that the front end will download
		if (fileLocation == null) {
			String insightFolder = this.insight.getInsightFolder();
			fileLocation = insightFolder + DIR_SEPARATOR + exportName;
			insightFile.setDeleteOnInsightClose(true);
		} else {
			fileLocation += DIR_SEPARATOR + exportName;
			insightFile.setDeleteOnInsightClose(false);
		}
		insightFile.setFilePath(fileLocation);
		exportMap.put("FILE_LOCATION", fileLocation);

		// Grab number of rows to export to know how many rows to iterate
		// through
		String limit = this.keyValue.get(ReactorKeysEnum.LIMIT.getKey());
		int numRowsToExport = -1;
		// If limit not set, export all rows
		if (limit != null) {
			try {
				numRowsToExport = Integer.parseInt(limit);
			} catch (NumberFormatException e) {
				logger.error(Constants.STACKTRACE, e);
			}
		}

		Map panelMap = this.insight.getInsightPanels();
		Map sheetMap = this.insight.getInsightSheets();
		
		GenRowStruct grs = this.store.getNoun(ReactorKeysEnum.PANEL_ORDER_IDS.getKey());
		
		/** If we need to send the map
		//((HashMap)this.store.getNoun("panelOrderIds").get(0)).get("a")
		// ((List)((HashMap)this.store.getNoun("panelOrderIds").get(0)).get("a")).get(0)
		
		// ExportToExcel ( panelOrderIds = [ { "a" : [ '1' , '2' ] } ] ) ;
		//this.store.getNoun("panelOrderIds").get(2)
		//orderOfPanelsMap = (HashMap)this.store.getNoun("panelOrderIds").get(0);
		*/
		List  orderOfPanels = null;
		//setting the order of panels for export
		if(grs != null) {
			orderOfPanels = new ArrayList(); 
			for(int idx = 0;idx < grs.size();idx++) {
				orderOfPanels.add(grs.get(idx) + "");
			}
		} else {
			orderOfPanels = new ArrayList(Arrays.asList(panelMap.keySet().toArray()));
		}

		// Use in-memory XSSF workbook to be able to plot charts

		// this should take care of templates too
		XSSFWorkbook workbook = getWorkBook();
		// create each sheet
		// this is purely for positioning where we put the panel
		for (String sheetId : sheetMap.keySet()) {
			InsightSheet sheet = sheetMap.get(sheetId);
			if (sheet == null) {
				continue;
			}
			String sheetName = sheet.getSheetLabel();
			if (sheetName == null) {
				// since we are 0 based, add 1
				try {
					sheetName = "Sheet" + (Integer.parseInt(sheetId) + 1);
				} catch (Exception ignore) {
					sheetName = "Sheet " + sheetId;
				}
			}
			// this is where the alias is being kept
			sheetAlias.put(sheetId, sheetName);
			HashMap sheetChartMap = new HashMap<>();
			sheetChartMap.put("colIndex", 0);
			sheetChartMap.put("rowIndex", 0);
			sheetChartMap.put("chartIndex", 1);
			this.chartPanelLayout.put(sheetId, sheetChartMap);
		}

		// iterate through panel map to figure out layout
		for (String panelId : orderOfPanels) {
			InsightPanel panel = panelMap.get(panelId);
			String sheetId = panel.getSheetId();
			// for each panel get the task and task options
			SelectQueryStruct qs = panel.getLastQs();
			TaskOptions taskOptions = panel.getLastTaskOptions();
			if (qs == null || taskOptions == null) {
				continue;
			}
			qs.setLimit(numRowsToExport);
			IQuerySelector firstSelector = qs.getSelectors().get(0);
			if (firstSelector.getSelectorType() == SELECTOR_TYPE.COLUMN) {
				qs.addOrderBy(firstSelector.getQueryStructName(), "ASC");
			} else {
				qs.addOrderBy(firstSelector.getAlias(), null, "ASC");
			}
			ITask task = InsightUtility.constructTaskFromQs(this.insight, qs);
			task.setLogger(this.getLogger(ExportToExcelReactor.class.getName()));
			task.setTaskOptions(taskOptions);
			Map panelChartMap = new HashMap<>();
			setChartLayout(panelChartMap, taskOptions, panelId);
			this.chartPanelLayout.get(sheetId).put(panelId, panelChartMap);
			String plotType = taskOptions.getLayout(panelId);
			//condition for stack bar chart its expecting different data format for stack
			if (plotType != null && (plotType.equals("Stack") || plotType.equals("MultiLine"))) {
				writeChartCategoryData(workbook, task, sheetId, panelId, panel.getPanelFormatValues());
			} else {
				writeData(workbook, task, sheetId, panelId, panel.getPanelFormatValues());
			}
		}

		// now build charts
		for (String panelId : orderOfPanels) {
			InsightPanel panel = panelMap.get(panelId);
			// for each panel get the task and task options
			SelectQueryStruct qs = panel.getLastQs();
			TaskOptions taskOptions = panel.getLastTaskOptions();
			if (qs == null || taskOptions == null) {
				continue;
			}
			ITask task = InsightUtility.constructTaskFromQs(this.insight, qs);
			task.setLogger(this.getLogger(ExportToExcelReactor.class.getName()));
			task.setTaskOptions(taskOptions);
			// add chart
			processTask(user, workbook, task, panel);
		}
		
		// Insert Semoss Logo after the last chart on each sheet
		//addLogo(workbook, sheetAlias);

		// rename sheets
		// not sure we need this
		/*
		for (String sheetId : sheetAlias.keySet()) {
			String sheetName = sheetAlias.get(sheetId);
			int sheetIndex = workbook.getSheetIndex(sheetId);
			if(sheetIndex >= 0) {
				workbook.setSheetName(sheetIndex, sheetName);
			}
		}*/

		
		// add the last row count
		// put the export map back
		// count is already added by the way of createBaseChart
		//putMap();
		
		// fill the headers
		String para1 = null;
		String para2 = null;
		
		if(exportMap.containsKey("para1")) {
			para1 = (String)exportMap.get("para1");
		}
		if(exportMap.containsKey("para2")) {
			para2 = (String)exportMap.get("para2");
		}
		
		// process and apply the audit param sheet if the export Audit has been opted
		// exportMap stores all the export related properties
		if (exportAudit) {
			makeParamSheet(workbook, this.insight,true, exportMap);
		}
		//moved the footer and header logic under export audit to apply headers and disclaimers
		if(para1 != null || para2 != null) {
			fillHeader(workbook, exportMap, para1, para2);
		}
		
		// fill the footers
		if(exportMap.containsKey("footer")) {
			fillFooter(workbook, exportMap, (String)exportMap.get("footer"));
		}
		
		// fill the place holders
		if(exportMap.containsKey("placeholders") && null!= exportMap.get("placeholders")) {
			fillPlaceholders(workbook, exportMap, (Map>) exportMap.get("placeholders"));
		}
		
		// remove the sheets after processing from the resulted export file
		removeSheet(workbook);
		
		// close the driver
		insight.getChromeDriver().quit(driver);
		/*
		if(driver != null && driver instanceof ChromeDriver) {
			((ChromeDriver)driver).quit();
		}*/

		// write / encrypt file
		String password = this.keyValue.get(ReactorKeysEnum.PASSWORD.getKey());
		if (password != null) {
			ExcelUtility.encrypt(workbook, fileLocation, password);
		} else {
			ExcelUtility.writeToFile(workbook, fileLocation);
		}
		
		// store the insight file 
		// in the insight so the FE can download it
		// only from the given insight
		this.insight.addExportFile(downloadKey, insightFile);
		return new NounMetadata(downloadKey, PixelDataType.CONST_STRING, PixelOperationType.FILE_DOWNLOAD);
	}
	
	public void processPayload() {
		super.processPayload();
		if(keyValue.containsKey(ReactorKeysEnum.HEIGHT.getKey())) {
			this.height = Integer.parseInt(keyValue.get(ReactorKeysEnum.HEIGHT.getKey())+"");
		} else if(exportMap.containsKey(ReactorKeysEnum.HEIGHT.getKey())) {
			this.height = Integer.parseInt(keyValue.get(ReactorKeysEnum.HEIGHT.getKey())+"");
		}
		
		if(keyValue.containsKey(ReactorKeysEnum.WIDTH.getKey())) {
			this.width = Integer.parseInt(keyValue.get(ReactorKeysEnum.WIDTH.getKey())+"");
		} else if(exportMap.containsKey(ReactorKeysEnum.WIDTH.getKey())) {
			this.width = Integer.parseInt(keyValue.get(ReactorKeysEnum.WIDTH.getKey())+"");
		}
	}
	
	private void addLogo(XSSFWorkbook workbook, Map sheetAlias) {
		String semossLogoPath = DIHelper.getInstance().getProperty("EXPORT_SEMOSS_LOGO");
		if (semossLogoPath != null) {
			File logo = new File(semossLogoPath);
			if (logo.exists()) {
				// Load image
				byte[] picture = null;
				try {
					picture = IOUtils.toByteArray(new FileInputStream(semossLogoPath));
				} catch (FileNotFoundException e) {
					logger.error(Constants.STACKTRACE, e);
				} catch (IOException ioe) {
					logger.error(Constants.STACKTRACE, ioe);
				}

				// Insert image into workbook
				int pictureIndex = workbook.addPicture(picture, Workbook.PICTURE_TYPE_PNG);

				// Insert logo into each sheet
				Iterator sheetIdIterator = sheetAlias.keySet().iterator();
				while (sheetIdIterator.hasNext()) {
					String sheetId = sheetIdIterator.next();
					// Get location for logo on current sheet
					Map sheetChartMap = this.chartPanelLayout.get(sheetId);
					int colIndex = (int) sheetChartMap.get("colIndex");
					// add an additional space
					colIndex++;
					int chartIndex = (int) sheetChartMap.get("chartIndex");
					// Helper returns an object that handles instantiating
					// concrete classes
					CreationHelper helper = workbook.getCreationHelper();
					int sheetIndex = workbook.getSheetIndex(sheetId);
					// if we have a sheet that is empty
					// it doesn't get created
					// so that will return -1
					// will also remove so we dont try to rename this
					// in the next step
					if (sheetIndex == -1) {
						sheetIdIterator.remove();
						continue;
					}
					XSSFSheet sheet = workbook.getSheetAt(sheetIndex);
					Drawing drawing = sheet.createDrawingPatriarch();
					// Create an anchor that is attached to the worksheet
					ClientAnchor anchor = helper.createClientAnchor();
					// Attach locations to anchor
					// The seemingly random numbers we're adding by are to make
					// the image look good/not stretched out
					anchor.setCol1(colIndex + 2);
					anchor.setRow1(chartIndex + 1);
					anchor.setCol2(colIndex + 8);
					anchor.setRow2(chartIndex + 4);
					// Create the picture
					Picture pict = drawing.createPicture(anchor, pictureIndex);
				}
			}
		}
	}

	private void setChartLayout(Map panelChartMap, TaskOptions taskOptions, String panelId) {
		String chartLayout = taskOptions.getLayout(panelId);
		panelChartMap.put("chartType", chartLayout);
		Map alignmentMap = taskOptions.getAlignmentMap(panelId);
		if (chartLayout.equals("Line") || chartLayout.equals("Area") || chartLayout.equals("Column")
				|| chartLayout.equals("Pie") || chartLayout.equals("Radar")) {
			List label = (List) alignmentMap.get("label");
			panelChartMap.put("x-axis", label);
			List yColumnNames = (List) alignmentMap.get("value");
			panelChartMap.put("y-axis", yColumnNames);
			for (String column : label) {
				panelChartMap.put(column, new HashMap<>());
			}
			for (String column : yColumnNames) {
				panelChartMap.put(column, new HashMap<>());
			}
		} else if (chartLayout.equals("Scatter")) {
			List label = (List) alignmentMap.get("label");
			panelChartMap.put("label", label);
			List x = (List) alignmentMap.get("x");
			panelChartMap.put("x-axis", x);
			List yColumnNames = (List) alignmentMap.get("y");
			panelChartMap.put("y-axis", yColumnNames);
			for (String column : label) {
				panelChartMap.put(column, new HashMap<>());
			}
		} // making accomodation for pivot
		else if (chartLayout.contentEquals("Pivot Table"))
		{
			// rows
			// columns
			// calculations
			List  rows = (List)alignmentMap.get("rows");
			List  columns = (List)alignmentMap.get("columns");
			List  calcs = (List)alignmentMap.get("calculations");
		}
	}

	private void processTask(User user, XSSFWorkbook workbook, ITask task, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();
		String sheetName = sheetAlias.get(sheetId);
		TaskOptions tOptions = task.getTaskOptions();
		Map options = tOptions.getOptions();
		XSSFSheet sheet = workbook.getSheet(sheetName);
		XSSFSheet dataSheet = workbook.getSheet(sheetName + "_Data");

		// Insert chart if supported
		try
		{
			String plotType = tOptions.getLayout(panelId);
			if (plotType.equals("Line")||plotType.equals("MultiLine")) {
				insertLineChart(sheet, dataSheet, options, panel);
			} else if (plotType.equals("Scatter")) {
				insertScatterChart(sheet, dataSheet,options, panel);
			} else if (plotType.equals("Area")) {
				insertAreaChart(sheet, dataSheet,options, panel);
			} else if (plotType.equals("Column") || plotType.equals("Stack")) {
				insertBarChart(sheet, dataSheet,options, panel);
			} else if (plotType.equals("Pie")) {
				insertPieChart(sheet, dataSheet,options, panel);
			} else if (plotType.equals("Radar")) {
				insertRadarChart(sheet, dataSheet,options, panel);
			} else if(!plotType.equals("Grid") && !plotType.equals("PivotTable")) { // do it only for non grid.. for grid we still need to do something else
				insertImage(workbook, user, sheet, sheetId, panelId);
			} else if (plotType.equals("Grid")) {
				insertGrid(sheet.getSheetName(), task, panel);
			} else if(plotType.equals("PivotTable")) { // do it only for non grid.. for grid we still need to do something else
				
				String pivRoutine = DIHelper.getInstance().getProperty("OPTIMIZE_PIVOT_EXPORT");
				if(pivRoutine != null && pivRoutine.equalsIgnoreCase("True"))
				{
					prerna.reactor.frame.py.CollectPivotReactor cpr = new prerna.reactor.frame.py.CollectPivotReactor();
					cpr.setNounStore(tOptions.getCollectStore());
					cpr.setInsight(insight);
					List rowObject = tOptions.getCollectStore().getNoun(cpr.keysToGet[0]).getAllValues();
					//cpr.
					insertPivot2(sheet.getSheetName(), cpr, rowObject);
				}
				else // old routine
					insertPivot(user, sheet.getSheetName(), panelId, sheetId);
			}
			
		} catch(Exception ex) {
			logger.error(Constants.STACKTRACE, ex);
			insight.getChromeDriver().quit(driver);

//			if(driver != null && driver instanceof ChromeDriver) {
//				((ChromeDriver)driver).quit();
//			}
			driver = null;
		} finally {
			insight.getChromeDriver().quit(driver);
//			if(driver != null && driver instanceof ChromeDriver) {
//				((ChromeDriver)driver).quit();
//			}
//			driver = null;
		}
	}

	private void writeData(XSSFWorkbook workbook, ITask task, String sheetId, String panelId, Map> panelFormatting) {
		CreationHelper createHelper = workbook.getCreationHelper();
		String sheetName = sheetAlias.get(sheetId);
		XSSFSheet sheet = workbook.getSheet(sheetName);
		if (sheet != null) {
			// create the data sheet as well
			sheet = workbook.getSheet(sheetName + "_Data");
		}
		if (sheet == null) {
			sheet = getSheet(workbook, sheetName);
			// also create a data sheet
			// also hide the sheet
			// no need to worry about creating template for data sheet
			sheet = workbook.createSheet(sheetName + "_Data");
			workbook.setSheetHidden(workbook.getSheetIndex(sheet), true);
		} 
		// since we write veriticlaly
		// shouldn't be doing this anymore
		// freeze the first row
//		sheet.createFreezePane(0, 1);

		int i = 0;
		int size = 0;
		// create typesArr as an array for faster searching
		String[] headers = null;
		SemossDataType[] typesArr = null;
		String[] additionalDataTypeArr = null;
		CellStyle[] stylingArr = null;
		
		// style dates
		CellStyle dateCellStyle = workbook.createCellStyle();
		dateCellStyle.setDataFormat(createHelper.createDataFormat().getFormat("dd-MM-yyyy"));
		// style timestamps
		CellStyle timeStampCellStyle = workbook.createCellStyle();
		timeStampCellStyle.setDataFormat(createHelper.createDataFormat().getFormat("dd-MM-yyyy HH:mm:ss"));

		// the excel data row
		Row excelRow = null;
		// the task data is being dumped vertically
		// we need to know where to start putting in data
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		int curSheetCol = 0;
		int endRow = (int) sheetMap.get("rowIndex");
		int excelRowCounter = endRow;

		// we need to iterate and write the headers during the first time
		if (task.hasNext()) {
			IHeadersDataRow row = task.next();
			List> headerInfo = task.getHeaderInfo();

			// create the header row
			Row headerRow = sheet.createRow(excelRowCounter++);
			
			// create a Font for styling header cells
			Font headerFont = workbook.createFont();
			headerFont.setBold(true);
			// create a CellStyle with the font
			CellStyle headerCellStyle = workbook.createCellStyle();
			headerCellStyle.setFont(headerFont);
			headerCellStyle.setAlignment(HorizontalAlignment.CENTER);
			headerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

			// generate the header row
			// and define constants used throughout like size, and types
			i = 0;
			headers = row.getHeaders();
			size = headers.length;
			typesArr = new SemossDataType[size];
			additionalDataTypeArr = new String[size];
			stylingArr = new CellStyle[size];
			for (; i < size; i++) {
				curSheetCol = i;
				Cell cell = headerRow.createCell(curSheetCol);
				getFormatedCellWithValue(cell, headers[i], SemossDataType.STRING, headerCellStyle);
				// grab metadata from iterator
				typesArr[i] = SemossDataType.convertStringToDataType(headerInfo.get(i).get("type") + "");
				additionalDataTypeArr[i] = headerInfo.get(i).get("additionalDataType") + "";
				try {
					stylingArr[i] = POIExportUtility.getCurrentStyle(workbook, additionalDataTypeArr[i], panelFormatting.get(headers[i])); 
				} catch(Exception e) {
					// ignore
				}
				if(stylingArr[i] == null) {
					if(typesArr[i] == SemossDataType.DATE) {
						stylingArr[i] = dateCellStyle;
					} else if(typesArr[i] == SemossDataType.TIMESTAMP) {
						stylingArr[i] = timeStampCellStyle;
					}
				}
			}

			// generate the data row
			excelRow = sheet.createRow(excelRowCounter++);
			Object[] dataRow = row.getValues();
			i = 0;
			for (; i < size; i++) {
				curSheetCol = i;
				Cell cell = excelRow.createCell(curSheetCol);
				Object value = dataRow[i];
				getFormatedCellWithValue(cell, value, typesArr[i], stylingArr[i]);
			}
		}

		// now iterate through all the data
		while (task.hasNext()) {
			excelRow = sheet.createRow(excelRowCounter++);
			IHeadersDataRow row = task.next();
			Object[] dataRow = row.getValues();
			i = 0;
			for (; i < size; i++) {
				curSheetCol = i;
				Cell cell = excelRow.createCell(curSheetCol);
				Object value = dataRow[i];
				getFormatedCellWithValue(cell, value, typesArr[i], stylingArr[i]);
			}
		}
		
		// add an additional empty row at the end
		// so we have some spacing between
		excelRow = sheet.createRow(excelRowCounter++);

		// Update col and row bounds for sheet
		// this keeps track at the sheet level where to add next task
		sheetMap.put("colIndex", 0);
		// add the offset of rows
		sheetMap.put("rowIndex", endRow + (excelRowCounter - endRow));		

		Map panelMap = (Map) sheetMap.get(panelId);

		// this map defines the start and end for each column
		if (headers != null && headers.length > 0) {
			List headerList = Arrays.asList(headers);
			for (String header : headers) {
				Map columnMap = new HashMap<>();
				columnMap.put("startRow", endRow + 1);
				// -2 for the extra line break between the data
				columnMap.put("endRow", excelRowCounter - 2);
				int headerIndex = headerList.indexOf(header);
				columnMap.put("startCol", headerIndex);
				columnMap.put("endCol", headerIndex);
				panelMap.put(header, columnMap);
			}
		}
	}

	private void insertLineChart(XSSFSheet sheet, XSSFSheet dataSheet, Map options, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();

		// retrieve ornaments
		Boolean gridOnX = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_X) + "");
		Boolean gridOnY = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_Y) + "");
		Boolean displayValues = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), DISPLAY_VALUES) + "");
        String yAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_Y_AXIS_TITLE) + "";
 		String xAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_X_AXIS_TITLE) + "";
 		Boolean showYAxisTitle = !panel.getOrnaments().isEmpty() && !yAxisFlag.isEmpty() && !yAxisFlag.equals("null") ? Boolean.parseBoolean(yAxisFlag) : true;
 		Boolean showXAxisTitle = !panel.getOrnaments().isEmpty() && !xAxisFlag.isEmpty() && !xAxisFlag.equals("null") ? Boolean.parseBoolean(xAxisFlag) : true;
 		String yAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), Y_AXIS_TITLE_NAME) + "" : "";
 		String xAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), X_AXIS_TITLE_NAME) + "" : "";
 		String colorName = panel.getMapInput(panel.getOrnaments(), COLOR_NAME) + "";
		Object customColors = panel.getMapInput(panel.getOrnaments(), CUSTOM_COLOR_ARRAY);
        Object colorObject = panel.getMapInput(panel.getOrnaments(), COLOR_ARRAY);
        String[] colorArray = POIExportUtility.getHexColorCode(colorName, customColors, colorObject);

		LegendPosition legendPosition = LegendPosition.TOP_RIGHT;
		AxisPosition bottomAxisPosition = AxisPosition.BOTTOM;
		AxisPosition leftAxisPosition = AxisPosition.LEFT;
		AxisCrosses leftAxisCrosses = AxisCrosses.AUTO_ZERO;
		ChartTypes chartType = ChartTypes.LINE;
		
		//get the options data
		Map optionData	=(Map) options.get(panelId);

		// Parse input data
		// label is name of column of x vals
		// value is name(s) of column(s) of y vals
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		Map panelMap = (Map) sheetMap.get(panelId);
		List label = (List) panelMap.get("x-axis");
		String xColumnName = label.get(0);
		List yColumnNames = (List) panelMap.get("y-axis");
		Map xColumnMap = (Map) panelMap.get(xColumnName);

		// Build chart
		XSSFChart chart = createBaseChart(sheet, sheetMap, legendPosition);
		XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(bottomAxisPosition);
		XDDFValueAxis leftAxis = chart.createValueAxis(leftAxisPosition);
		POIExportUtility.addGridLines(gridOnX, gridOnY, chart);
		leftAxis.setCrosses(leftAxisCrosses);

		// Add Y Axis Title
		if(showYAxisTitle) {
			if(!yAxisTitleName.isEmpty() && !yAxisTitleName.equals("null")) {
				leftAxis.setTitle(yAxisTitleName);
			} else {
				if ("MultiLine".equals(optionData.get("layout"))) {
					leftAxis.setTitle(String.join(", ", (List) ((Map) optionData.get("alignment")).get("value")).replace("_",
							" "));
				} else {
					leftAxis.setTitle(String.join(", ", yColumnNames).replace("_", " "));
				}
			}
		}
		// Add X Axis Title
		if(showXAxisTitle) {
			if(!xAxisTitleName.isEmpty() && !xAxisTitleName.equals("null")) {
				bottomAxis.setTitle(xAxisTitleName);
			} else {
				bottomAxis.setTitle(xColumnName.replace("_", " "));
			}
		}

		XDDFLineChartData data = (XDDFLineChartData) chart.createData(chartType, bottomAxis, leftAxis);

		// Add in x vals
		// do it based on data sheet
		
		XDDFNumericalDataSource xs = createXAxis(dataSheet, xColumnMap);

		// Add in y vals
		int yCounter = 0;
		for (int i = 0; i < yColumnNames.size(); i++) {
			Map yColumnMap = (Map) panelMap.get(yColumnNames.get(i));
			XDDFNumericalDataSource ys = createYAxis(dataSheet, yColumnMap);
			XDDFLineChartData.Series chartSeries = (XDDFLineChartData.Series) data.addSeries(xs, ys);
			chartSeries.setTitle(yColumnNames.get(i).replace("_", " "), null);
			// Standardize markers
			XDDFSolidFillProperties fillProperties = new XDDFSolidFillProperties();
			fillProperties.setColor(XDDFColor.from(POIExportUtility.hex2Rgb(colorArray[yCounter%colorArray.length])));
			chartSeries.setMarkerStyle(MarkerStyle.CIRCLE);
			XDDFShapeProperties propertiesMarker = new XDDFShapeProperties();
			propertiesMarker.setFillProperties(fillProperties);
			chart.getCTChart().getPlotArea().getLineChartArray(0).getSerArray(i).getMarker().addNewSpPr()
					.set(propertiesMarker.getXmlObject());
			// Standardize line
			XDDFLineProperties lineProperties = new XDDFLineProperties();
			lineProperties.setFillProperties(fillProperties);
			chartSeries.setLineProperties(lineProperties);
			yCounter++;
		}

		// add the title
		Object chartTitle = panel.getMapInput(panel.getOrnaments(), CHART_TITLE);
		if(chartTitle != null) {
			chart.setTitleText(chartTitle + "");
		}
		chart.plot(data);

		// if true, display data labels on chart
		if (displayValues.booleanValue()) {
			POIExportUtility.displayValues(ChartTypes.LINE, chart);
		}
	}
	
	private void insertScatterChart(XSSFSheet sheet, XSSFSheet dataSheet, Map options, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();

		// retrieve ornaments
		Boolean gridOnX = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_X) + "");
		Boolean gridOnY = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_Y) + "");
		Boolean displayValues = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), DISPLAY_VALUES) + "");
		String yAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_Y_AXIS_TITLE) + "";
		String xAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_X_AXIS_TITLE) + "";
		Boolean showYAxisTitle = !panel.getOrnaments().isEmpty() && !yAxisFlag.isEmpty() && !yAxisFlag.equals("null") ? Boolean.parseBoolean(yAxisFlag) : true;
		Boolean showXAxisTitle = !panel.getOrnaments().isEmpty() && !xAxisFlag.isEmpty() && !xAxisFlag.equals("null") ? Boolean.parseBoolean(xAxisFlag) : true;
		String yAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), Y_AXIS_TITLE_NAME) + "" : "";
		String xAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), X_AXIS_TITLE_NAME) + "" : "";

		LegendPosition legendPosition = LegendPosition.TOP_RIGHT;
		AxisPosition bottomAxisPosition = AxisPosition.BOTTOM;
		AxisPosition leftAxisPosition = AxisPosition.LEFT;
		AxisCrosses leftAxisCrosses = AxisCrosses.AUTO_ZERO;
		ChartTypes chartType = ChartTypes.SCATTER;

		// Parse input data
		// label is name of column of x vals
		// value is name(s) of column(s) of y vals
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		Map panelMap = (Map) sheetMap.get(panelId);
		List label = (List) panelMap.get("x-axis");
		String xColumnName = label.get(0);
		List yColumnNames = (List) panelMap.get("y-axis");
		Map xColumnMap = (Map) panelMap.get(xColumnName);

		// Build chart
		XSSFChart chart = createBaseChart(sheet, sheetMap, null);
		XDDFValueAxis bottomAxis = chart.createValueAxis(bottomAxisPosition);
		XDDFValueAxis leftAxis = chart.createValueAxis(leftAxisPosition);
	//	leftAxis.setMinimum(0.4);
		POIExportUtility.addGridLines(gridOnX, gridOnY, chart);
		leftAxis.setCrosses(leftAxisCrosses);

		if(showYAxisTitle) {
			if(!yAxisTitleName.isEmpty() && !yAxisTitleName.equals("null")) {
				leftAxis.setTitle(yAxisTitleName);
			} else {
				leftAxis.setTitle(String.join(", ", yColumnNames).replace("_", " "));
			}
		}
		if(showXAxisTitle) {
			if(!xAxisTitleName.isEmpty() && !xAxisTitleName.equals("null")) {
				bottomAxis.setTitle(xAxisTitleName);
			} else {
				bottomAxis.setTitle(xColumnName.replace("_", " "));
			}
		}

		XDDFScatterChartData data = (XDDFScatterChartData) chart.createData(chartType, bottomAxis, leftAxis);
		// Add in x vals
		XDDFDataSource xs = createXAxis(dataSheet, xColumnMap);

		// Add in y vals
		for (int i = 0; i < yColumnNames.size(); i++) {
			String yColumnName = yColumnNames.get(i);
			Map yColumnMap = (Map) panelMap.get(yColumnName);
			XDDFNumericalDataSource ys = createYAxis(dataSheet, yColumnMap);
			XDDFScatterChartData.Series chartSeries = (XDDFScatterChartData.Series) data.addSeries(xs, ys);
			chartSeries.setTitle(yColumnName.replace("_", " "), null);
			chartSeries.setSmooth(false);
			chartSeries.setMarkerStyle(MarkerStyle.CIRCLE);
			CTScatterChart scatterSeries = chart.getCTChart().getPlotArea().getScatterChartArray(0);
			scatterSeries.getSerArray(i).addNewSpPr().addNewLn().addNewNoFill();
			scatterSeries.addNewVaryColors().setVal(false);
		}
		
		// add the title
		Object chartTitle = panel.getMapInput(panel.getOrnaments(), CHART_TITLE);
		if(chartTitle != null) {
			chart.setTitleText(chartTitle + "");
		}
		chart.plot(data);
		
		// if true, display data labels on chart
		if (displayValues.booleanValue()) {
			POIExportUtility.displayValues(ChartTypes.SCATTER, chart);
		}
	}

	private void insertBarChart(XSSFSheet sheet, XSSFSheet dataSheet, Map options, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();

		// retrieve ornaments
		Boolean toggleStack = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), "tools.shared.toggleStack") + "");
		Boolean flipAxis = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), "tools.shared.rotateAxis") + "");
		Boolean gridOnX = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_X) + "");
		Boolean gridOnY = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_Y) + "");
		Boolean displayValues = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), DISPLAY_VALUES) + "");
		String displayValuesPosition = panel.getMapInput(panel.getOrnaments(), "tools.shared.customizeBarLabel.position") + "";
		String yAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_Y_AXIS_TITLE) + "";
		String xAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_X_AXIS_TITLE) + "";
		Boolean showYAxisTitle = !panel.getOrnaments().isEmpty() && !yAxisFlag.isEmpty() && !yAxisFlag.equals("null") ? Boolean.parseBoolean(yAxisFlag) : true;
		Boolean showXAxisTitle = !panel.getOrnaments().isEmpty() && !xAxisFlag.isEmpty() && !xAxisFlag.equals("null") ? Boolean.parseBoolean(xAxisFlag) : true;
		String yAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), Y_AXIS_TITLE_NAME) + "" : "";
		String xAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), X_AXIS_TITLE_NAME) + "" : "";
		String colorName = panel.getMapInput(panel.getOrnaments(), COLOR_NAME) + "";
		Object customColors = panel.getMapInput(panel.getOrnaments(), CUSTOM_COLOR_ARRAY);
        Object colorObject = panel.getMapInput(panel.getOrnaments(), COLOR_ARRAY);
        String[] colorArray = POIExportUtility.getHexColorCode(colorName, customColors, colorObject);
        
        
		LegendPosition legendPosition = LegendPosition.TOP_RIGHT;
		AxisPosition bottomAxisPosition = AxisPosition.BOTTOM;
		AxisPosition leftAxisPosition = AxisPosition.LEFT;
		AxisCrosses leftAxisCrosses = AxisCrosses.AUTO_ZERO;
		ChartTypes chartType = ChartTypes.BAR;
		//get the options data
		Map optionData	=(Map) options.get(panelId);

		// Parse input data
		// label is name of column of x vals
		// value is name(s) of column(s) of y vals
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		Map panelMap = (Map) sheetMap.get(panelId);
		List label = (List) panelMap.get("x-axis");
		String xColumnName = label.get(0);
		List yColumnNames = (List) panelMap.get("y-axis");
		Map xColumnMap = (Map) panelMap.get(xColumnName);

		// Build chart
		XSSFChart chart = createBaseChart(sheet, sheetMap, legendPosition);
		//chart.setTitleText("Title Test");
		XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(bottomAxisPosition);
		
		XDDFValueAxis leftAxis = chart.createValueAxis(leftAxisPosition);
		leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
		POIExportUtility.addGridLines(gridOnX, gridOnY, chart);
		leftAxis.setCrosses(leftAxisCrosses);

		// Add Y Axis Title
		if(showYAxisTitle) {
			if(!yAxisTitleName.isEmpty() && !yAxisTitleName.equals("null")) {
				leftAxis.setTitle(yAxisTitleName);
			} else {
				if ("Stack".equals(optionData.get("layout"))) {
					leftAxis.setTitle(String.join(", ", (List) ((Map) optionData.get("alignment")).get("value")).replace("_",
							" "));
				} else {
				leftAxis.setTitle(String.join(", ", yColumnNames).replace("_", " "));
			}
		}}
		// Add X Axis Title
		if(showXAxisTitle) {
			if(!xAxisTitleName.isEmpty() && !xAxisTitleName.equals("null")) {
				bottomAxis.setTitle(xAxisTitleName);
			} else {
				bottomAxis.setTitle(xColumnName.replace("_", " "));
			}
		}

		XDDFBarChartData data = (XDDFBarChartData) chart.createData(chartType, bottomAxis, leftAxis);

		if (flipAxis) {
			data.setBarDirection(BarDirection.BAR);
		} else {
			data.setBarDirection(BarDirection.COL);
		}
		if("Stack".equals(optionData.get("layout"))){
			toggleStack= !toggleStack;
		}

		if (toggleStack) {
			data.setBarGrouping(BarGrouping.STACKED);
			// correcting the overlap so bars really are stacked and not side by side
			chart.getCTChart().getPlotArea().getBarChartArray(0).addNewOverlap().setVal((byte) 100);
		}
		data.setGapWidth(10);

		// Add in x vals
		XDDFNumericalDataSource xs = createXAxis(dataSheet, xColumnMap);

		// Add in y vals
		int yCounter = 0;
		for (String yColumnName : yColumnNames) {
			Map yColumnMap = (Map) panelMap.get(yColumnName);
			XDDFNumericalDataSource ys = createYAxis(dataSheet, yColumnMap);
			XDDFBarChartData.Series chartSeries = (XDDFBarChartData.Series) data.addSeries(xs, ys);
			XDDFSolidFillProperties fillProperties = new XDDFSolidFillProperties();
			fillProperties.setColor(XDDFColor.from(POIExportUtility.hex2Rgb(colorArray[yCounter%colorArray.length])));
            chartSeries.setFillProperties(fillProperties);
			chartSeries.setTitle(yColumnName!=null ? yColumnName.toString().replace("_", " "):null, null);
			yCounter++;
		}

		// add the title
		Object chartTitle = panel.getMapInput(panel.getOrnaments(), CHART_TITLE);
		if(chartTitle != null) {
			chart.setTitleText(chartTitle + "");
		}
		chart.plot(data);

		// if true, display data labels on chart
		if (displayValues.booleanValue()) {
			CTDLbls dLbls = POIExportUtility.displayValues(ChartTypes.BAR, chart);
			POIExportUtility.positionDisplayValues(ChartTypes.BAR, dLbls, displayValuesPosition);
		}
	}
	
	private void insertAreaChart(XSSFSheet sheet, XSSFSheet dataSheet, Map options, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();

		// retrieve ornaments
		Boolean gridOnX = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_X) + "");
		Boolean gridOnY = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_Y) + "");
		Boolean displayValues = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), DISPLAY_VALUES) + "");
        String yAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_Y_AXIS_TITLE) + "";
 		String xAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_X_AXIS_TITLE) + "";
 		Boolean showYAxisTitle = !panel.getOrnaments().isEmpty() && !yAxisFlag.isEmpty() && !yAxisFlag.equals("null") ? Boolean.parseBoolean(yAxisFlag) : true;
 		Boolean showXAxisTitle = !panel.getOrnaments().isEmpty() && !xAxisFlag.isEmpty() && !xAxisFlag.equals("null") ? Boolean.parseBoolean(xAxisFlag) : true;
 		String yAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), Y_AXIS_TITLE_NAME) + "" : "";
 		String xAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), X_AXIS_TITLE_NAME) + "" : "";
 		String colorName = panel.getMapInput(panel.getOrnaments(), COLOR_NAME) + "";
		Object customColors = panel.getMapInput(panel.getOrnaments(), CUSTOM_COLOR_ARRAY);
        Object colorObject = panel.getMapInput(panel.getOrnaments(), COLOR_ARRAY);
        String[] colorArray = POIExportUtility.getHexColorCode(colorName, customColors, colorObject);
        
		LegendPosition legendPosition = LegendPosition.TOP_RIGHT;
		AxisPosition bottomAxisPosition = AxisPosition.BOTTOM;
		AxisPosition leftAxisPosition = AxisPosition.LEFT;
		AxisCrosses leftAxisCrosses = AxisCrosses.AUTO_ZERO;
		ChartTypes chartType = ChartTypes.AREA;

		// Parse input data
		// label is name of column of x vals
		// value is name(s) of column(s) of y vals
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		Map panelMap = (Map) sheetMap.get(panelId);
		List label = (List) panelMap.get("x-axis");
		String xColumnName = label.get(0);
		List yColumnNames = (List) panelMap.get("y-axis");
		Map xColumnMap = (Map) panelMap.get(xColumnName);

		// Build chart
		XSSFChart chart = createBaseChart(sheet, sheetMap, legendPosition);
		XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(bottomAxisPosition);
		XDDFValueAxis leftAxis = chart.createValueAxis(leftAxisPosition);
		POIExportUtility.addGridLines(gridOnX, gridOnY, chart);
		leftAxis.setCrosses(leftAxisCrosses);

		// Add Y Axis Title
		if(showYAxisTitle) {
			if(!yAxisTitleName.isEmpty() && !yAxisTitleName.equals("null")) {
				leftAxis.setTitle(yAxisTitleName);
			} else {
				leftAxis.setTitle(String.join(", ", yColumnNames).replace("_", " "));
			}
		}
		// Add X Axis Title
		if(showXAxisTitle) {
			if(!xAxisTitleName.isEmpty() && !xAxisTitleName.equals("null")) {
				bottomAxis.setTitle(xAxisTitleName);
			} else {
				bottomAxis.setTitle(xColumnName.replace("_", " "));
			}
		}

		XDDFAreaChartData data = (XDDFAreaChartData) chart.createData(chartType, bottomAxis, leftAxis);

		// Add in x vals
		XDDFNumericalDataSource xs = createXAxis(dataSheet, xColumnMap);

		// Add in y vals
		int yCounter = 0;
		for (String yColumnName : yColumnNames) {
			Map yColumnMap = (Map) panelMap.get(yColumnName);
			XDDFNumericalDataSource ys = createYAxis(dataSheet, yColumnMap);
			XDDFAreaChartData.Series chartSeries = (XDDFAreaChartData.Series) data.addSeries(xs, ys);
			XDDFSolidFillProperties fillProperties = new XDDFSolidFillProperties();
			fillProperties.setColor(XDDFColor.from(POIExportUtility.hex2Rgb(colorArray[yCounter%colorArray.length])));
			chartSeries.setFillProperties(fillProperties);
			chartSeries.setTitle(yColumnName.replace("_", " "), null);
			yCounter++;
		}

		// add the title
		Object chartTitle = panel.getMapInput(panel.getOrnaments(), CHART_TITLE);
		if(chartTitle != null) {
			chart.setTitleText(chartTitle + "");
		}
		chart.plot(data);

		// if true, display data labels on chart
		if (displayValues.booleanValue()) {
			POIExportUtility.displayValues(ChartTypes.AREA, chart);
		}
	}

	private void insertPieChart(XSSFSheet sheet, XSSFSheet dataSheet,  Map options, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();

		// retrieve ornaments
		Boolean displayValues = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), DISPLAY_VALUES) + "");
		String displayValuesPosition = panel.getMapInput(panel.getOrnaments(), "tools.shared.customizePieLabel.position") + "";
		List pieCustomDisplayValues = (List) panel.getMapInput(panel.getOrnaments(), "tools.shared.customizePieLabel.dimension");
		
		LegendPosition legendPosition = LegendPosition.TOP_RIGHT;
		AxisPosition bottomAxisPosition = AxisPosition.BOTTOM;
		AxisPosition leftAxisPosition = AxisPosition.LEFT;
		AxisCrosses leftAxisCrosses = AxisCrosses.AUTO_ZERO;
		ChartTypes chartType = ChartTypes.PIE;

		// Parse input data
		// label is name of column of x vals
		// value is name(s) of column(s) of y vals
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		Map panelMap = (Map) sheetMap.get(panelId);
		List label = (List) panelMap.get("x-axis");
		String xColumnName = label.get(0);
		List yColumnNames = (List) panelMap.get("y-axis");
		Map xColumnMap = (Map) panelMap.get(xColumnName);

		// Build chart
		XSSFChart chart = createBaseChart(sheet, sheetMap, legendPosition);
		XDDFPieChartData data = (XDDFPieChartData) chart.createData(chartType, null, null);

		// Add in x vals
		XDDFNumericalDataSource xs = createXAxis(dataSheet, xColumnMap);

		// Add in y vals
		for (String yColumnName : yColumnNames) {
			Map yColumnMap = (Map) panelMap.get(yColumnName);
			XDDFNumericalDataSource ys = createYAxis(dataSheet, yColumnMap);
			XDDFPieChartData.Series chartSeries = (XDDFPieChartData.Series) data.addSeries(xs, ys);
			chartSeries.setTitle(yColumnName.replace("_", " "), null);
			chartSeries.setExplosion((long) 0);
		}

		Object chartTitle = panel.getMapInput(panel.getOrnaments(), CHART_TITLE);
		if(chartTitle != null) {
			chart.setTitleText(chartTitle + "");
		}
		chart.plot(data);

		// if true, display data labels on chart
		if (displayValues.booleanValue()) {
			CTPieChart ctPieChart = chart.getCTChart().getPlotArea().getPieChartArray(0);
            ctPieChart.addNewDLbls();
            CTDLbls dLbls = ctPieChart.getDLbls();
            if(dLbls != null) {
            	if(pieCustomDisplayValues.contains("Percentage")) {
                    dLbls.addNewShowPercent().setVal(true);
            	} else {
                    dLbls.addNewShowPercent().setVal(false);
            	}
            	if(pieCustomDisplayValues.contains("Value")) {
                    dLbls.addNewShowVal().setVal(true);
            	} else {
                    dLbls.addNewShowVal().setVal(false);
            	}
            	if(pieCustomDisplayValues.contains("Name")) {
                    dLbls.addNewShowCatName().setVal(true);
            	} else {
                    dLbls.addNewShowCatName().setVal(false);
            	}
            	dLbls.addNewShowBubbleSize().setVal(false);
                dLbls.addNewShowLegendKey().setVal(false);
                dLbls.addNewShowSerName().setVal(false);
    			POIExportUtility.positionDisplayValues(ChartTypes.PIE, dLbls, displayValuesPosition);
            }
		}
	}

	private void insertRadarChart(XSSFSheet sheet, XSSFSheet dataSheet, Map options, InsightPanel panel) {
		String panelId = panel.getPanelId();
		String sheetId = panel.getSheetId();

		// retrieve ornaments
		Boolean gridOnX = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_X) + "");
		Boolean gridOnY = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRID_ON_Y) + "");
        String yAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_Y_AXIS_TITLE) + "";
 		String xAxisFlag = panel.getMapInput(panel.getOrnaments(), SHOW_X_AXIS_TITLE) + "";
 		Boolean showYAxisTitle = !panel.getOrnaments().isEmpty() && !yAxisFlag.isEmpty() && !yAxisFlag.equals("null") ? Boolean.parseBoolean(yAxisFlag) : true;
 		Boolean showXAxisTitle = !panel.getOrnaments().isEmpty() && !xAxisFlag.isEmpty() && !xAxisFlag.equals("null") ? Boolean.parseBoolean(xAxisFlag) : true;
 		String yAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), Y_AXIS_TITLE_NAME) + "" : "";
 		String xAxisTitleName = !panel.getOrnaments().isEmpty() ? panel.getMapInput(panel.getOrnaments(), X_AXIS_TITLE_NAME) + "" : "";		             

		LegendPosition legendPosition = LegendPosition.TOP_RIGHT;
		AxisPosition bottomAxisPosition = AxisPosition.BOTTOM;
		AxisPosition leftAxisPosition = AxisPosition.LEFT;
		AxisCrosses leftAxisCrosses = AxisCrosses.AUTO_ZERO;
		ChartTypes chartType = ChartTypes.RADAR;

		// Parse input data
		// label is name of column of x vals
		// value is name(s) of column(s) of y vals
		Map sheetMap = this.chartPanelLayout.get(sheetId);
		Map panelMap = (Map) sheetMap.get(panelId);
		List label = (List) panelMap.get("x-axis");
		String xColumnName = label.get(0);
		List yColumnNames = (List) panelMap.get("y-axis");
		Map xColumnMap = (Map) panelMap.get(xColumnName);

		// Build chart
		XSSFChart chart = createBaseChart(sheet, sheetMap, legendPosition);
		XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(bottomAxisPosition);
		XDDFValueAxis leftAxis = chart.createValueAxis(leftAxisPosition);
		POIExportUtility.addGridLines(gridOnX, gridOnY, chart);
		leftAxis.setCrosses(leftAxisCrosses);

		// Add Y Axis Title
		if(showYAxisTitle) {
			if(!yAxisTitleName.isEmpty() && !yAxisTitleName.equals("null")) {
				leftAxis.setTitle(yAxisTitleName);
			} else {
				leftAxis.setTitle(String.join(", ", yColumnNames).replace("_", " "));
			}
		}
		// Add X Axis Title
		if(showXAxisTitle) {
			if(!xAxisTitleName.isEmpty() && !xAxisTitleName.equals("null")) {
				bottomAxis.setTitle(xAxisTitleName);
			} else {
				bottomAxis.setTitle(xColumnName.replace("_", " "));
			}
		}

		XDDFRadarChartData data = (XDDFRadarChartData) chart.createData(chartType, bottomAxis, leftAxis);

		// Add in x vals
		XDDFNumericalDataSource xs = createXAxis(dataSheet, xColumnMap);

		// Add in y vals
		for (String yColumnName : yColumnNames) {
			Map yColumnMap = (Map) panelMap.get(yColumnName);
			XDDFNumericalDataSource ys = createYAxis(dataSheet, yColumnMap);
			XDDFRadarChartData.Series chartSeries = (XDDFRadarChartData.Series) data.addSeries(xs, ys);
			chartSeries.setTitle(yColumnName.replace("_", " "), null);
		}

		// add the title
		Object chartTitle = panel.getMapInput(panel.getOrnaments(), CHART_TITLE);
		if(chartTitle != null) {
			chart.setTitleText(chartTitle + "");
		}
		chart.plot(data);
	}

	// this is where the chart is being placed. Need to see this properly
	private XSSFChart createBaseChart(XSSFSheet sheet, Map sheetMap, LegendPosition legendPosition) {
		XSSFDrawing drawing = sheet.createDrawingPatriarch();
		// Put chart to the right of any data columns
		int colIndex = (int) sheetMap.get("colIndex");
		int chartIndex = (int) sheetMap.get("chartIndex");
		// drawing can be at 0 ,0
		int drawingColIndex = startColumn + this.columnGutter ;
		int sheetLastRow = 0; 
		if(exportMap.containsKey(sheet.getSheetName() + "ROW_COUNT"))
			sheetLastRow = Integer.parseInt(exportMap.get(sheet.getSheetName() + "ROW_COUNT") + "");
		
		XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, drawingColIndex, sheetLastRow, drawingColIndex + width,
				sheetLastRow + height);
		// Increment for positioning other objects correctly
		sheetMap.put("chartIndex", chartIndex + height + rowGutter);
		XSSFChart chart = drawing.createChart(anchor);
		if(legendPosition != null) {
			XDDFChartLegend legend = chart.getOrAddLegend();
			legend.setPosition(legendPosition);
		}
		sheetLastRow = sheetLastRow + height + rowGutter;
		exportMap.put(sheet.getSheetName() + "ROW_COUNT", sheetLastRow);
				
		return chart;
	}

	private XDDFNumericalDataSource createXAxis(XSSFSheet sheet, Map xColumnMap) {
		
		int xStartCol = (int) xColumnMap.get("startCol");
		int xEndCol = (int) xColumnMap.get("endCol");
		int xStartRow = (int) xColumnMap.get("startRow");
		int xEndRow = (int) xColumnMap.get("endRow");
		CellRangeAddress xsCellRange = new CellRangeAddress(xStartRow, xEndRow, xStartCol, xEndCol);
		XDDFNumericalDataSource xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, xsCellRange);

		return xs;
	}

	private XDDFNumericalDataSource createYAxis(XSSFSheet sheet, Map yColumnMap) {
		int yStartCol = (int) yColumnMap.get("startCol");
		int yEndCol = (int) yColumnMap.get("endCol");
		int yStartRow = (int) yColumnMap.get("startRow");
		int yEndRow = (int) yColumnMap.get("endRow");
		CellRangeAddress ysCellRange = new CellRangeAddress(yStartRow, yEndRow, yStartCol, yEndCol);
		XDDFNumericalDataSource ys = XDDFDataSourcesFactory.fromNumericCellRange(sheet, ysCellRange);

		return ys;
	}
	
	private void insertPivot(User user, String excelSheetName, String panelId, String sheetId) {
		//http://localhost:9090/semoss/#!/html?engine=95079463-9643-474a-be55-cca8bf91b358&id=735f32dd-4ec0-46ce-b2fa-4194cc270c7a&panel=0 
		//http://localhost:9090/semoss/#!/html?insightId=95079463-9643-474a-be55-cca8bf91b358&panel=0  
		// http://localhost:8080/appui/#!/html?insightId=d08a5e71-af2f-43d8-89e1-f806ff0527ea&panel=5 - this worked
		String baseUrl = this.insight.getBaseURL();
		String sessionId = ThreadStore.getSessionId();
		String htmlUrl = baseUrl + "html?insightId=" + insight.getInsightId() + "&sheet=" + sheetId + "&panel=" + panelId;
		logger.info("Generating pivot at " + htmlUrl);
		if(driver == null) {
			//driver = ChromeDriverUtility.makeChromeDriver(baseUrl, htmlUrl,  800, 600);
			driver = insight.getChromeDriver().makeChromeDriver(baseUrl, htmlUrl,  800, 600);
		}
		logger.info("Generating pivot view");
		
		String exportName = AbstractExportTxtReactor.getExportFileName(user, "ABCD", "png");
		String imageLocation = this.insight.getInsightFolder() + DIR_SEPARATOR + exportName;

		//this.insight.getChromeDriver().captureImagePersistent(driver, baseUrl, htmlUrl, imageLocation, sessionId, 10_000);
		
		String html2 = insight.getChromeDriver().captureDataPersistent(driver, baseUrl, htmlUrl, sessionId, 10_000);
		
		insight.getChromeDriver().quit(driver);
		driver = null;

		//logger.info(" HTML from Capture " + html2);
		//html2 = insight.getChromeDriver().getHTML(driver, "//html/body//table");
		//logger.info(" HTML from getHTML " + html2);
		//WebElement we = driver.findElement(By.xpath("//html/body//table"));
		//String html2 = driver.executeScript("return arguments[0].outerHTML;", we) + "";
		
		//WebElement elem1 = new WebDriverWait(driver, 10)
		//        .until(ExpectedConditions.elementToBeClickable(By.xpath("//html/body//table")));
		//html = driver.executeScript("return document.documentElement.outerHTML;") + "";
		//System.out.println(html);
		//System.out.println(html2);
		//driver.quit();
		//driver = null; 
		
		TableToXLSXReactor txl = new TableToXLSXReactor();
		txl.exportMap = exportMap;
		txl.html = html2;
		txl.sheetName = excelSheetName;
		String fileName = (String)exportMap.get("FILE_NAME");
		
		txl.processTable(excelSheetName, html2, fileName);
		logger.info("Done processing pivot");
	}
	
	private void insertPivot2(String excelSheetName, prerna.reactor.frame.py.CollectPivotReactor cpr, List rows) {
		//http://localhost:9090/semoss/#!/html?engine=95079463-9643-474a-be55-cca8bf91b358&id=735f32dd-4ec0-46ce-b2fa-4194cc270c7a&panel=0 
		//http://localhost:9090/semoss/#!/html?insightId=95079463-9643-474a-be55-cca8bf91b358&panel=0  
		// http://localhost:8080/appui/#!/html?insightId=d08a5e71-af2f-43d8-89e1-f806ff0527ea&panel=5 - this worked

		//logger.info(" HTML from Capture " + html2);
		//html2 = insight.getChromeDriver().getHTML(driver, "//html/body//table");
		//logger.info(" HTML from getHTML " + html2);
		//WebElement we = driver.findElement(By.xpath("//html/body//table"));
		//String html2 = driver.executeScript("return arguments[0].outerHTML;", we) + "";
		
		//WebElement elem1 = new WebDriverWait(driver, 10)
		//        .until(ExpectedConditions.elementToBeClickable(By.xpath("//html/body//table")));
		//html = driver.executeScript("return document.documentElement.outerHTML;") + "";
		//System.out.println(html);
		//System.out.println(html2);
		//driver.quit();
		//driver = null; 
		NounMetadata retData = cpr.execute();
		
		// you have what you need now..
		ConstantDataTask cdt = (ConstantDataTask)retData.getValue();
		// json is sitting in the cdt
		String json = (String)((Map)cdt.getOutputData()).get("values");

		JSONArray array = new JSONArray(json);
		StringBuffer html2 = new StringBuffer();
		for(int secIndex = 1;secIndex < array.length();secIndex++)
		{
			JSONObject obj = array.getJSONArray(secIndex).getJSONObject(0);
			html2.append(cpr.getJson2HTML(obj, rows));
		}
		
		TableToXLSXReactor txl = new TableToXLSXReactor();
		txl.exportMap = exportMap;
		txl.html = html2.toString();
		txl.sheetName = excelSheetName;
		String fileName = (String)exportMap.get("FILE_NAME");
		
		txl.processTable(excelSheetName, html2.toString(), fileName);
		logger.info("Done processing pivot");
	}

	
	/**
	 * Creating Html content and passed TableToXLSXReactor
	 * @param excelSheetName  
	 * @param task complete data 
	 * @param panel insight panel information
	 */
	private void insertGrid(String excelSheetName, ITask task, InsightPanel panel) {
		//get the string HTML from task
		TableToXLSXReactor txl = new TableToXLSXReactor();
		//it contains the all the param info
		txl.exportMap = exportMap;
		txl.sheetName = excelSheetName;
		String fileName = (String) exportMap.get("FILE_NAME");
		Boolean gridSpanRows = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRIDSPANROWS) + "");

		String[] headers = task.getHeaderInfo().stream().map(hdr->{
			return (String)hdr.get("header");
		}).collect(Collectors.toList()).stream().toArray(String[]::new);
		
		List> headerInfo = task.getHeaderInfo();
		SemossDataType[] typesArr = new SemossDataType[headers.length];
		for (int i = 0; i < headers.length; i++) {
			typesArr[i] = SemossDataType.convertStringToDataType(headerInfo.get(i).get("type") + "");
		}

		//Putting the datatypes array of grid headers into export map
		exportMap.put(DATA_TYPES_ARRAY_KEY, typesArr);
		txl.isGrid = true;
		txl.processTable(excelSheetName, generateGridHtml(task, panel), fileName);
		if(gridSpanRows) {
			txl.mergeAreas();
		}
		logger.info("Done processing grid");
	}


	/**
	 * 
	 * @param wb
	 * @param targetSheet
	 * @param sheetId
	 * @param panelId
	 */
	private void insertImage(Workbook wb, User user, XSSFSheet targetSheet, String sheetId, String panelId) {
		String baseUrl = this.insight.getBaseURL();
		String sessionId = ThreadStore.getSessionId();
		String imageUrl = this.insight.getLiveURL();
		String panelAppender = "&panel=" + panelId;
		String sheetAppender = "&sheet=" + sheetId;
		
		String prefixName = Utility.getRandomString(8);
		String exportName = AbstractExportTxtReactor.getExportFileName(user, prefixName, "png");
		String imageLocation = this.insight.getInsightFolder() + DIR_SEPARATOR + exportName;

		if(driver == null) {
			//driver = ChromeDriverUtility.makeChromeDriver(baseUrl, imageUrl + sheetAppender + panelAppender, 800, 600);
			driver = this.insight.getChromeDriver().makeChromeDriver(baseUrl, imageUrl + sheetAppender + panelAppender, 800, 600);
		}
		// download this file
		//ChromeDriverUtility.captureImagePersistent(driver, baseUrl, imageUrl + sheetAppender + panelAppender, imageLocation, sessionId);
		this.insight.getChromeDriver().captureImagePersistent(driver, baseUrl, imageUrl + sheetAppender + panelAppender, imageLocation, sessionId, 10_000);

		
		insight.getChromeDriver().quit(driver);
		driver = null;
		
		// download this file
		//ChromeDriverUtility.captureImage(baseUrl, imageUrl + sheetAppender + panelAppender, fileLocation, sessionId, 800, 600, true);
		// write this to the sheet now
		int sheetLastRow = 0; 
		if(exportMap.containsKey(targetSheet.getSheetName() + "ROW_COUNT"))
			sheetLastRow = Integer.parseInt(exportMap.get(targetSheet.getSheetName() + "ROW_COUNT") + "");

		//1920 x 936
		//FileInputStream obtains input bytes from the image file
		try {
			InputStream inputStream = new FileInputStream(Utility.normalizePath(imageLocation));
			//Get the contents of an InputStream as a byte[].
			byte[] bytes = IOUtils.toByteArray(inputStream);
			//Adds a picture to the workbook
			int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
			//close the input stream
			inputStream.close();

			FileUtils.forceDelete(new File(Utility.normalizePath(imageLocation)));

			//Returns an object that handles instantiating concrete classes
			CreationHelper helper = wb.getCreationHelper();
			//Creates the top-level drawing patriarch.
			Drawing drawing = targetSheet.createDrawingPatriarch();

			//Create an anchor that is attached to the worksheet
			ClientAnchor anchor = helper.createClientAnchor();

			
			//create an anchor with upper left cell _and_ bottom right cell
			anchor.setCol1(startColumn); //Column B
			anchor.setRow1(sheetLastRow); //Row 3
			anchor.setCol2(startColumn + width); //Column C // doesnt matter
			anchor.setRow2(sheetLastRow+height); //Row 4

			//Creates a picture
			Picture pict = drawing.createPicture(anchor, pictureIdx);
			//pict.resize();

			//Reset the image to the original size
			//pict.resize(); //don't do that. Let the anchor resize the image!
			//Create the Cell B3
			Cell cell = targetSheet.createRow(2).createCell(1);
		} catch (IOException e) {
			logger.error(Constants.STACKTRACE, e);
		}

		sheetLastRow = sheetLastRow + height + rowGutter;
		exportMap.put(targetSheet.getSheetName() + "ROW_COUNT", sheetLastRow);		
	}
	
	/*
	 * generate HTML string from the grid data
	 * 
	 * task contains the dataframe
	 * panel contains the all the ornaments and panel formats and color by values
	 */
	private String generateGridHtml(ITask task, InsightPanel panel) {
        // get the gridSpanRows param from the ornaments for the grid rowspan
		Boolean gridSpanRows = Boolean.parseBoolean(panel.getMapInput(panel.getOrnaments(), GRIDSPANROWS) + "");
		Map> panelFormatting = panel.getPanelFormatValues();
		// get the color by value details like on which  data we have to apply the color
		Map> colorByValueMap = getColorByValueData(panel);

		StringBuilder html = new StringBuilder();
		String[] headers = null;
		List> headerInfo = null;
		List rowList = new ArrayList<>();

		logger.info("Generating html view");
		// now we have the data, create the table
		html.append("");
		// create the header
		if (task.hasNext()) {
			IHeadersDataRow row = task.next();
			headerInfo = task.getHeaderInfo();
			headers = row.getHeaders();
			
			html.append("");
			html.append("");
			// creating header row
			for (String header : headers) {
				html.append("");
			}
			html.append("");
			html.append("");
			
			// creating body
			html.append("");
			// add the first row to the list
			rowList.add(row.getValues());
			// adding the rest of the rows
			while (task.hasNext()) {
				row = task.next();
				rowList.add(row.getValues());
			}

			int[] rowSpan = new int[headers.length];
			for (int rowIdx = 0, rowLen = rowList.size(); rowIdx < rowLen; rowIdx++) {
				Object[] rowData = rowList.get(rowIdx);
				// creating data rows
				html.append("");
				for (int colIdx = 0, colLen = rowData.length; colIdx < colLen; colIdx++) {
					Object cell = rowData[colIdx];
					// check for row span flag
					if (gridSpanRows) {
						if (rowSpan[colIdx] > 1) {
							rowSpan[colIdx]--;
							continue;
						}
						// restart the spanning
						rowSpan[colIdx] = 1;
						// look at the next row
						for (int nextIdx = rowIdx + 1; nextIdx < rowLen; nextIdx++) {
							Object next = rowList.get(nextIdx)[colIdx];
							
							// Check if the current cell is equal to the next cell
							if (cell == next || (cell != null && next != null && cell.equals(next))) {
								// increment
								rowSpan[colIdx]++;								
							}
							//break the loop if current row cell and next row cell are not equal.
							else {
								break;
							}
						}
					}
					// get the background color of each cell or rows
					Object cellColor = FormattingUtility.getBackgroundColor(colorByValueMap, headers, rowData, colIdx);
					//get the formatted data values based on formatdatavalue tool applied 
					Object formattedDataValue = FormattingUtility.formatDataValues(
							cell,
							(String) headerInfo.get(colIdx).get("dataType"),
							(String) headerInfo.get(colIdx).get("additionalDataType"),
							panelFormatting.get(headers[colIdx]));
					//getting rowspancount as String
				   String rowSpanCount= rowSpan[colIdx] > 1 ? String.valueOf(rowSpan[colIdx]):""; 

					// creating td with data and styles (rowspan if applicable)
					html.append("");
				}
				html.append("");
			}
			html.append("");
			html.append("
" + header + "
" + formattedDataValue+ "
"); } // write html to your C drive for testing purpose // WriteToFile(html.toString(), "test.html"); return html.toString(); } /** * This method returns the map with color by value rules and the raw values to * apply color on * @param panel * @return */ private Map> getColorByValueData(InsightPanel panel) { // Using LinkedHashMap - To Maintain insertion order Map> colorByValueMap = new LinkedHashMap<>(); for (ColorByValueRule cbv : panel.getColorByValue()) { // you can grab the query struct SelectQueryStruct cbvQS = cbv.getQueryStruct(); // turn the query struct to a task // you can iterator through to know which values to paint ITask cbvTask = InsightUtility.constructTaskFromQs(this.insight, cbvQS); cbvTask.setLogger(this.getLogger(ExportToExcelReactor.class.getName())); List colorByValues = new ArrayList<>(); while (cbvTask.hasNext()) { colorByValues.add(cbvTask.next().getRawValues()[0]); } colorByValueMap.put(cbv, colorByValues); } return colorByValueMap; } //transform the data for stackbar and multiline chart private void writeChartCategoryData(XSSFWorkbook workbook, ITask task, String sheetId, String panelId, Map> panelFormatting) { CreationHelper createHelper = workbook.getCreationHelper(); String sheetName = sheetAlias.get(sheetId); XSSFSheet sheet = workbook.getSheet(sheetName); if (sheet != null) { // create the data sheet as well sheet = workbook.getSheet(sheetName + "_Data"); } if (sheet == null) { sheet = getSheet(workbook, sheetName); // also create a data sheet // also hide the sheet // no need to worry about creating template for data sheet sheet = workbook.createSheet(sheetName + "_Data"); workbook.setSheetHidden(workbook.getSheetIndex(sheet), true); } // since we write veriticlaly // shouldn't be doing this anymore // freeze the first row // sheet.createFreezePane(0, 1); int size = 0; // create typesArr as an array for faster searching String[] headers = null; SemossDataType[] typesArr = null; String[] additionalDataTypeArr = null; CellStyle[] stylingArr = null; // style dates CellStyle dateCellStyle = workbook.createCellStyle(); dateCellStyle.setDataFormat(createHelper.createDataFormat().getFormat("dd-MM-yyyy")); // style timestamps CellStyle timeStampCellStyle = workbook.createCellStyle(); timeStampCellStyle.setDataFormat(createHelper.createDataFormat().getFormat("dd-MM-yyyy HH:mm:ss")); // the excel data row Row excelRow = null; // the task data is being dumped vertically // we need to know where to start putting in data Map sheetMap = this.chartPanelLayout.get(sheetId); int curSheetCol = 0; int endRow = (int) sheetMap.get("rowIndex"); int excelRowCounter = endRow; Row headerRow = null; Map xAxisToRow = new HashMap<>(); List currentHeaderValues = new ArrayList<>(); CellStyle headerCellStyle = null; int xAxisIndex = 0; int yAxisIndex = 1; int instanceColumnIndex = 2; // we need to iterate and write the headers during the first time if (task.hasNext()) { IHeadersDataRow row = task.next(); List> headerInfo = task.getHeaderInfo(); // create the header row headerRow = sheet.createRow(excelRowCounter++); // create a Font for styling header cells Font headerFont = workbook.createFont(); headerFont.setBold(true); // create a CellStyle with the font headerCellStyle = workbook.createCellStyle(); headerCellStyle.setFont(headerFont); headerCellStyle.setAlignment(HorizontalAlignment.CENTER); headerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // generate the header row // and define constants used throughout like size, and types headers = row.getHeaders(); size = headers.length; typesArr = new SemossDataType[size]; additionalDataTypeArr = new String[size]; stylingArr = new CellStyle[size]; for (int i = 0; i < size; i++) { // grab metadata from iterator typesArr[i] = SemossDataType.convertStringToDataType(headerInfo.get(i).get("type") + ""); additionalDataTypeArr[i] = headerInfo.get(i).get("additionalDataType") + ""; try { stylingArr[i] = POIExportUtility.getCurrentStyle(workbook, additionalDataTypeArr[i], panelFormatting.get(headers[i])); } catch(Exception e) { // ignore } if(stylingArr[i] == null) { if(typesArr[i] == SemossDataType.DATE) { stylingArr[i] = dateCellStyle; } else if(typesArr[i] == SemossDataType.TIMESTAMP) { stylingArr[i] = timeStampCellStyle; } } } // we are creating our own table // where the data will come as // x-axis, y-axis value, split-for-columns // but we generate // x-axis, split-for-columns 1, split-for-columns 2 // and the values will be what we get { currentHeaderValues.add(headers[0]); Cell cell = headerRow.createCell(0); cell.setCellValue(headers[0]); cell.setCellStyle(headerCellStyle); } // generate the first data row excelRow = sheet.createRow(excelRowCounter++); Object[] dataRow = row.getValues(); // now we transpose this row to put it properly in the excel Object xAxisValue = dataRow[xAxisIndex]; xAxisToRow.put(xAxisValue + "", excelRow); Cell cell = excelRow.createCell(0); getFormatedCellWithValue(cell, xAxisValue, typesArr[xAxisIndex], stylingArr[xAxisIndex]); Object instanceValue = dataRow[yAxisIndex]; Object instanceColumn = dataRow[instanceColumnIndex]; if(!currentHeaderValues.contains(instanceColumn + "")) { currentHeaderValues.add(instanceColumn + ""); cell = headerRow.createCell(currentHeaderValues.size()-1); getFormatedCellWithValue(cell, instanceColumn, typesArr[instanceColumnIndex], headerCellStyle); } cell = excelRow.createCell(currentHeaderValues.indexOf(instanceColumn + "")); getFormatedCellWithValue(cell, instanceValue, typesArr[yAxisIndex], stylingArr[yAxisIndex]); } // now iterate through all the data while (task.hasNext()) { IHeadersDataRow row = task.next(); Object[] dataRow = row.getValues(); Cell cell = null; Object xAxisValue = dataRow[xAxisIndex]; if(xAxisToRow.containsKey(xAxisValue + "")) { excelRow = xAxisToRow.get(xAxisValue + ""); } else { excelRow = sheet.createRow(excelRowCounter++); xAxisToRow.put(xAxisValue + "", excelRow); // set the x axis value once cell = excelRow.createCell(0); getFormatedCellWithValue(cell, xAxisValue, typesArr[xAxisIndex], stylingArr[xAxisIndex]); } Object instanceValue = dataRow[yAxisIndex]; Object instanceColumn = dataRow[instanceColumnIndex]; if(!currentHeaderValues.contains(instanceColumn + "")) { currentHeaderValues.add(instanceColumn + ""); cell = headerRow.createCell(currentHeaderValues.size()-1); getFormatedCellWithValue(cell, instanceColumn, typesArr[instanceColumnIndex], headerCellStyle); } cell = excelRow.createCell(currentHeaderValues.indexOf(instanceColumn + "")); getFormatedCellWithValue(cell, instanceValue, typesArr[yAxisIndex], stylingArr[yAxisIndex]); } // add an additional empty row at the end // so we have some spacing between excelRow = sheet.createRow(excelRowCounter++); // Update col and row bounds for sheet // this keeps track at the sheet level where to add next task sheetMap.put("colIndex", 0); // add the offset of rows sheetMap.put("rowIndex", endRow + (excelRowCounter - endRow)); Map panelMap = (Map) sheetMap.get(panelId); // this map defines the start and end for each column if (headers != null && headers.length > 0) { List headerList = Arrays.asList(headers); for (String header : headers) { Map columnMap = new HashMap<>(); columnMap.put("startRow", endRow + 1); // -2 for the extra line break between the data columnMap.put("endRow", excelRowCounter - 2); int headerIndex = headerList.indexOf(header); columnMap.put("startCol", headerIndex); columnMap.put("endCol", headerIndex); panelMap.put(header, columnMap); } } // add an additional empty row at the end // so we have some spacing between excelRow = sheet.createRow(excelRowCounter++); // Update col and row bounds for sheet // this keeps track at the sheet level where to add next task sheetMap.put("colIndex", 0); // add the offset of rows sheetMap.put("rowIndex", endRow + (excelRowCounter - endRow)); // set x axis and y axis data panelMap.put("x-axis", Arrays.asList(currentHeaderValues.get(0))); panelMap.put("y-axis", currentHeaderValues.subList(1, currentHeaderValues.size())); // this map defines the start and end for each column for (String header : currentHeaderValues) { Map columnMap = new HashMap<>(); columnMap.put("startRow", endRow + 1); // -3 for the extra line break between the data columnMap.put("endRow", excelRowCounter - 3); int headerIndex = currentHeaderValues.indexOf(header); columnMap.put("startCol", headerIndex); columnMap.put("endCol", headerIndex); panelMap.put(header, columnMap); } } // sets the format and value to cell private Cell getFormatedCellWithValue(Cell cell, Object value, SemossDataType dataType, CellStyle cellStyle) { if (value == null || value.toString().length() == 0) { cell.setCellValue(""); } else { if (dataType == SemossDataType.STRING || value instanceof String) { cell.setCellValue(value + ""); } else if (dataType == SemossDataType.INT || dataType == SemossDataType.DOUBLE) { cell.setCellValue(((Number) value).doubleValue()); } else if (dataType == SemossDataType.DATE) { if (value instanceof SemossDate) { cell.setCellValue(((SemossDate) value).getDate()); } else { cell.setCellValue(value + ""); } } else if (dataType == SemossDataType.TIMESTAMP) { if (value instanceof SemossDate) { cell.setCellValue(((SemossDate) value).getDate()); } else { cell.setCellValue(value + ""); } } else if (dataType == SemossDataType.BOOLEAN) { cell.setCellValue((boolean) value); } else { cell.setCellValue(value + ""); } if (cellStyle != null) { cell.setCellStyle(cellStyle); } } return cell; } /* * write file to the local for testing purpose * * public static void WriteToFile(String fileContent, String fileName) { try{ * String projectPath = "C:\\workspace"; String tempFile = projectPath + * File.separator+fileName; File file = new File(tempFile); // if file does * exists, then delete and create a new file //write to file with * OutputStreamWriter OutputStream outputStream = new * FileOutputStream(file.getAbsoluteFile()); Writer writer=new * OutputStreamWriter(outputStream); writer.write(fileContent); writer.close();} * catch(Exception e){ System.out.println(e); } * * } */ }