package tim.prune.function.charts;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import tim.prune.App;
import tim.prune.ExternalTools;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.DataPoint;
import tim.prune.data.Distance;
import tim.prune.data.Field;
import tim.prune.data.Timestamp;
import tim.prune.data.Track;
import tim.prune.data.Distance.Units;
import tim.prune.load.GenericFileFilter;

/**
 * Class to manage the generation of charts using gnuplot
 */
public class Charter extends GenericFunction
{
	/** dialog object, cached */
	private JDialog _dialog = null;
	/** radio button for distance axis */
	private JRadioButton _distanceRadio = null;
	/** radio button for time axis */
	private JRadioButton _timeRadio = null;
	/** array of checkboxes for specifying y axes */
	private JCheckBox[] _yAxesBoxes = null;
	/** radio button for svg output */
	private JRadioButton _svgRadio = null;
	/** file chooser for saving svg file */
	private JFileChooser _fileChooser = null;
	/** text field for svg width */
	private JTextField _svgWidthField = null;
	/** text field for svg height */
	private JTextField _svgHeightField = null;

	/** Default dimensions of Svg file */
	private static final String DEFAULT_SVG_WIDTH  = "800";
	private static final String DEFAULT_SVG_HEIGHT = "400";


	/**
	 * Constructor from superclass
	 * @param inApp app object
	 */
	public Charter(App inApp)
	{
		super(inApp);
	}

	/**
	 * @return key for function name
	 */
	public String getNameKey()
	{
		return "function.charts";
	}

	/**
	 * Show the dialog
	 */
	public void begin()
	{
		// First check if gnuplot is available
		if (!ExternalTools.isToolInstalled(ExternalTools.TOOL_GNUPLOT))
		{
			_app.showErrorMessage(getNameKey(), "dialog.charts.gnuplotnotfound");
			return;
		}
		// Make dialog window
		if (_dialog == null)
		{
			_dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
			_dialog.setLocationRelativeTo(_parentFrame);
			_dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			_dialog.getContentPane().add(makeDialogComponents());
			_dialog.pack();
		}
		if (setupDialog(_app.getTrackInfo().getTrack())) {
			_dialog.setVisible(true);
		}
		else {
			_app.showErrorMessage(getNameKey(), "dialog.charts.needaltitudeortimes");
		}
	}


	/**
	 * Make the dialog components
	 * @return panel containing gui elements
	 */
	private JPanel makeDialogComponents()
	{
		JPanel dialogPanel = new JPanel();
		dialogPanel.setLayout(new BorderLayout());

		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
		// x axis choice
		JPanel axisPanel = new JPanel();
		axisPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.charts.xaxis")));
		_distanceRadio = new JRadioButton(I18nManager.getText("fieldname.distance"));
		_distanceRadio.setSelected(true);
		_timeRadio = new JRadioButton(I18nManager.getText("fieldname.time"));
		ButtonGroup axisGroup = new ButtonGroup();
		axisGroup.add(_distanceRadio); axisGroup.add(_timeRadio);
		axisPanel.add(_distanceRadio); axisPanel.add(_timeRadio);
		mainPanel.add(axisPanel);

		// y axis choices
		JPanel yPanel = new JPanel();
		yPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.charts.yaxis")));
		_yAxesBoxes = new JCheckBox[4]; // dist altitude speed vertspeed (time not available on y axis)
		_yAxesBoxes[0] = new JCheckBox(I18nManager.getText("fieldname.distance"));
		_yAxesBoxes[1] = new JCheckBox(I18nManager.getText("fieldname.altitude"));
		_yAxesBoxes[1].setSelected(true);
		_yAxesBoxes[2] = new JCheckBox(I18nManager.getText("fieldname.speed"));
		_yAxesBoxes[3] = new JCheckBox(I18nManager.getText("fieldname.verticalspeed"));
		for (int i=0; i<4; i++) {
			yPanel.add(_yAxesBoxes[i]);
		}
		mainPanel.add(yPanel);

		// Add validation to prevent choosing invalid (ie dist/dist) combinations
		ActionListener xAxisListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				enableYbox(0, _timeRadio.isSelected());
			}
		};
		_timeRadio.addActionListener(xAxisListener);
		_distanceRadio.addActionListener(xAxisListener);

		// output buttons
		JPanel outputPanel = new JPanel();
		outputPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.charts.output")));
		outputPanel.setLayout(new BorderLayout());
		JPanel radiosPanel = new JPanel();
		JRadioButton screenRadio = new JRadioButton(I18nManager.getText("dialog.charts.screen"));
		screenRadio.setSelected(true);
		_svgRadio = new JRadioButton(I18nManager.getText("dialog.charts.svg"));
		ButtonGroup outputGroup = new ButtonGroup();
		outputGroup.add(screenRadio); outputGroup.add(_svgRadio);
		radiosPanel.add(screenRadio); radiosPanel.add(_svgRadio);
		outputPanel.add(radiosPanel, BorderLayout.NORTH);
		// panel for svg width, height
		JPanel sizePanel = new JPanel();
		sizePanel.setLayout(new GridLayout(2, 2, 10, 1));
		JLabel widthLabel = new JLabel(I18nManager.getText("dialog.charts.svgwidth"));
		widthLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		sizePanel.add(widthLabel);
		_svgWidthField = new JTextField(DEFAULT_SVG_WIDTH, 5);
		sizePanel.add(_svgWidthField);
		JLabel heightLabel = new JLabel(I18nManager.getText("dialog.charts.svgheight"));
		heightLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		sizePanel.add(heightLabel);
		_svgHeightField = new JTextField(DEFAULT_SVG_HEIGHT, 5);
		sizePanel.add(_svgHeightField);

		outputPanel.add(sizePanel, BorderLayout.EAST);
		mainPanel.add(outputPanel);
		dialogPanel.add(mainPanel, BorderLayout.CENTER);

		// button panel on bottom
		JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
		// ok button
		JButton okButton = new JButton(I18nManager.getText("button.ok"));
		okButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showChart(_app.getTrackInfo().getTrack());
				_dialog.setVisible(false);
			}
		});
		buttonPanel.add(okButton);
		// Cancel button
		JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
		cancelButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				_dialog.setVisible(false);
			}
		});
		buttonPanel.add(cancelButton);
		dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
		return dialogPanel;
	}


	/**
	 * Set up the dialog according to the track contents
	 * @param inTrack track object
	 * @return true if it's all ok
	 */
	private boolean setupDialog(Track inTrack)
	{
		boolean hasTimes = inTrack.hasData(Field.TIMESTAMP);
		boolean hasAltitudes = inTrack.getAltitudeRange().hasRange();
		_timeRadio.setEnabled(hasTimes);

		// Add checks to prevent choosing unavailable combinations
		if (!hasTimes) {
			_distanceRadio.setSelected(true);
		}
		enableYbox(0, !_distanceRadio.isSelected());
		enableYbox(1, hasAltitudes);
		enableYbox(2, hasTimes);
		enableYbox(3, hasTimes && hasAltitudes);
		return (hasTimes || hasAltitudes);
	}


	/**
	 * Enable or disable the given y axis checkbox
	 * @param inIndex index of checkbox
	 * @param inFlag true to enable
	 */
	private void enableYbox(int inIndex, boolean inFlag)
	{
		_yAxesBoxes[inIndex].setEnabled(inFlag);
		if (!inFlag) {
			_yAxesBoxes[inIndex].setSelected(inFlag);
		}
	}

	/**
	 * Show the chart for the specified track
	 * @param inTrack track object containing data
	 */
	private void showChart(Track inTrack)
	{
		int numCharts = 0;
		for (int i=0; i<_yAxesBoxes.length; i++) {
			if (_yAxesBoxes[i].isSelected()) {
				numCharts++;
			}
		}
		// Select default chart if none selected
		if (numCharts == 0) {
			_yAxesBoxes[1].setSelected(true);
			numCharts = 1;
		}
		int[] heights = getHeights(numCharts);

		boolean showSvg = _svgRadio.isSelected();
		File svgFile = null;
		if (showSvg) {
			svgFile = selectSvgFile();
			if (svgFile == null) {showSvg = false;}
		}
		OutputStreamWriter writer = null;
		try
		{
			final String gnuplotPath = Config.getConfigString(Config.KEY_GNUPLOT_PATH);
			Process process = Runtime.getRuntime().exec(gnuplotPath + " -persist");
			writer = new OutputStreamWriter(process.getOutputStream());
			if (showSvg)
			{
				writer.write("set terminal svg size " + getSvgValue(_svgWidthField, DEFAULT_SVG_WIDTH) + " "
					+ getSvgValue(_svgHeightField, DEFAULT_SVG_HEIGHT) + "\n");
				writer.write("set out '" + svgFile.getAbsolutePath() + "'\n");
			}
			if (numCharts > 1) {
				writer.write("set multiplot layout " + numCharts + ",1\n");
			}
			// Loop over possible charts
			int chartNum = 0;
			for (int c=0; c<_yAxesBoxes.length; c++)
			{
				if (_yAxesBoxes[c].isSelected())
				{
					writer.write("set size 1," + (0.01*heights[chartNum*2+1]) + "\n");
					writer.write("set origin 0," + (0.01*heights[chartNum*2]) + "\n");
					writeChart(writer, inTrack, _distanceRadio.isSelected(), c);
					chartNum++;
				}
			}
			// Close multiplot if open
			if (numCharts > 1) {
				writer.write("unset multiplot\n");
			}
		}
		catch (Exception e) {
			_app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
		}
		finally {
			try {
				// Close writer
				if (writer != null) writer.close();
			}
			catch (Exception e) {} // ignore
		}
	}


	/**
	 * Parse the given text field's value and return as string
	 * @param inField text field to read from
	 * @param inDefault default value if not valid
	 * @return value of svg dimension as string
	 */
	private static String getSvgValue(JTextField inField, String inDefault)
	{
		int value = 0;
		try {
			value = Integer.parseInt(inField.getText());
		}
		catch (Exception e) {} // ignore, value stays zero
		if (value > 0) {
			return "" + value;
		}
		return inDefault;
	}


	/**
	 * Write out the selected chart to the given Writer object
	 * @param inWriter writer object
	 * @param inTrack Track containing data
	 * @param inDistance true if x axis is distance
	 * @param inYaxis index of y axis
	 * @throws IOException if writing error occurred
	 */
	private static void writeChart(OutputStreamWriter inWriter, Track inTrack, boolean inDistance, int inYaxis)
	throws IOException
	{
		ChartSeries xValues = null, yValues = null;
		ChartSeries distValues = getDistanceValues(inTrack);
		// Choose x values according to axis
		if (inDistance) {
			xValues = distValues;
		}
		else {
			xValues = getTimeValues(inTrack);
		}
		// Choose y values according to axis
		switch (inYaxis)
		{
		case 0: // y axis is distance
			yValues = distValues;
			break;
		case 1: // y axis is altitude
			yValues = getAltitudeValues(inTrack);
			break;
		case 2: // y axis is speed
			yValues = getSpeedValues(inTrack);
			break;
		case 3: // y axis is vertical speed
			yValues = getVertSpeedValues(inTrack);
			break;
		}
		// Make a temporary data file for the output (one per subchart)
		File tempFile = File.createTempFile("prunedata", null);
		tempFile.deleteOnExit();
		// write out values for x and y to temporary file
		FileWriter tempFileWriter = null;
		try {
			tempFileWriter = new FileWriter(tempFile);
			tempFileWriter.write("# Temporary data file for GpsPrune charts\n\n");
			for (int i=0; i<inTrack.getNumPoints(); i++) {
				if (xValues.hasData(i) && yValues.hasData(i)) {
					tempFileWriter.write("" + xValues.getData(i) + ", " + yValues.getData(i) + "\n");
				}
			}
		}
		catch (IOException ioe) { // rethrow
			throw ioe;
		}
		finally {
			try {
				tempFileWriter.close();
			}
			catch (Exception e) {}
		}

		// Set x axis label
		if (inDistance) {
			inWriter.write("set xlabel '" + I18nManager.getText("fieldname.distance") + " (" + getUnitsLabel("units.kilometres.short", "units.miles.short") + ")'\n");
		}
		else {
			inWriter.write("set xlabel '" + I18nManager.getText("fieldname.time") + " (" + I18nManager.getText("units.hours") + ")'\n");
		}

		// set other labels and plot chart
		String chartTitle = null;
		switch (inYaxis)
		{
		case 0: // y axis is distance
			inWriter.write("set ylabel '" + I18nManager.getText("fieldname.distance") + " (" + getUnitsLabel("units.kilometres.short", "units.miles.short") + ")'\n");
			chartTitle = I18nManager.getText("fieldname.distance");
			break;
		case 1: // y axis is altitude
			inWriter.write("set ylabel '" + I18nManager.getText("fieldname.altitude") + " (" + getUnitsLabel("units.metres.short", "units.feet.short") + ")'\n");
			chartTitle = I18nManager.getText("fieldname.altitude");
			break;
		case 2: // y axis is speed
			inWriter.write("set ylabel '" + I18nManager.getText("fieldname.speed") + " (" + getUnitsLabel("units.kmh", "units.mph") + ")'\n");
			chartTitle = I18nManager.getText("fieldname.speed");
			break;
		case 3: // y axis is vertical speed
			inWriter.write("set ylabel '" + I18nManager.getText("fieldname.verticalspeed") + " (" + getUnitsLabel("units.metrespersec", "units.feetpersec") + ")'\n");
			chartTitle = I18nManager.getText("fieldname.verticalspeed");
			break;
		}
		inWriter.write("set style fill solid 0.5 border -1\n");
		inWriter.write("plot '" + tempFile.getAbsolutePath() + "' title '" + chartTitle + "' with filledcurve y1=0 lt rgb \"#009000\"\n");
	}

	/**
	 * Get the units label for the given keys
	 * @param inMetric key if metric
	 * @param inImperial key if imperial
	 * @return display label with appropriate text
	 */
	private static String getUnitsLabel(String inMetric, String inImperial)
	{
		String key = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?inMetric:inImperial;
		return I18nManager.getText(key);
	}


	/**
	 * Calculate the distance values for each point in the given track
	 * @param inTrack track object
	 * @return distance values in a ChartSeries object
	 */
	private static ChartSeries getDistanceValues(Track inTrack)
	{
		// Calculate distances and fill in in values array
		ChartSeries values = new ChartSeries(inTrack.getNumPoints());
		double totalRads = 0;
		DataPoint prevPoint = null, currPoint = null;
		for (int i=0; i<inTrack.getNumPoints(); i++)
		{
			currPoint = inTrack.getPoint(i);
			if (prevPoint != null && !currPoint.isWaypoint() && !currPoint.getSegmentStart())
			{
				totalRads += DataPoint.calculateRadiansBetween(prevPoint, currPoint);
			}
			if (Config.getConfigBoolean(Config.KEY_METRIC_UNITS)) {
				values.setData(i, Distance.convertRadiansToDistance(totalRads, Units.KILOMETRES));
			} else {
				values.setData(i, Distance.convertRadiansToDistance(totalRads, Units.MILES));
			}
			prevPoint = currPoint;
		}
		return values;
	}

	/**
	 * Calculate the time values for each point in the given track
	 * @param inTrack track object
	 * @return time values in a ChartSeries object
	 */
	private static ChartSeries getTimeValues(Track inTrack)
	{
		// Calculate times and fill in in values array
		ChartSeries values = new ChartSeries(inTrack.getNumPoints());
		double seconds = 0.0;
		Timestamp prevTimestamp = null;
		DataPoint currPoint = null;
		for (int i=0; i<inTrack.getNumPoints(); i++)
		{
			currPoint = inTrack.getPoint(i);
			if (currPoint.hasTimestamp())
			{
				if (!currPoint.getSegmentStart() && prevTimestamp != null) {
					seconds += (currPoint.getTimestamp().getSecondsSince(prevTimestamp));
				}
				values.setData(i, seconds / 60.0 / 60.0);
				prevTimestamp = currPoint.getTimestamp();
			}
		}
		return values;
	}

	/**
	 * Calculate the altitude values for each point in the given track
	 * @param inTrack track object
	 * @return altitude values in a ChartSeries object
	 */
	private static ChartSeries getAltitudeValues(Track inTrack)
	{
		ChartSeries values = new ChartSeries(inTrack.getNumPoints());
		Altitude.Format altFormat = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?Altitude.Format.METRES:Altitude.Format.FEET;
		for (int i=0; i<inTrack.getNumPoints(); i++) {
			if (inTrack.getPoint(i).hasAltitude()) {
				values.setData(i, inTrack.getPoint(i).getAltitude().getValue(altFormat));
			}
		}
		return values;
	}

	/**
	 * Calculate the speed values for each point in the given track
	 * @param inTrack track object
	 * @return speed values in a ChartSeries object
	 */
	private static ChartSeries getSpeedValues(Track inTrack)
	{
		// Calculate speeds and fill in in values array
		ChartSeries values = new ChartSeries(inTrack.getNumPoints());
		DataPoint prevPoint = null, currPoint = null, nextPoint = null;
		DataPoint[] points = getDataPoints(inTrack, false);
		final boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
		// Loop over collected points
		for (int i=1; i<(points.length-1); i++)
		{
			prevPoint = points[i-1];
			currPoint = points[i];
			nextPoint = points[i+1];
			if (prevPoint != null && currPoint != null && nextPoint != null
				&& nextPoint.getTimestamp().isAfter(currPoint.getTimestamp())
				&& currPoint.getTimestamp().isAfter(prevPoint.getTimestamp()))
			{
				// Calculate average speed between prevPoint and nextPoint
				double rads = DataPoint.calculateRadiansBetween(prevPoint, currPoint)
					+ DataPoint.calculateRadiansBetween(currPoint, nextPoint);
				double time = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp()) / 60.0 / 60.0;
				// Convert to distance and pass to chartseries
				if (useMetric) {
					values.setData(i, Distance.convertRadiansToDistance(rads, Units.KILOMETRES) / time);
				} else {
					values.setData(i, Distance.convertRadiansToDistance(rads, Units.MILES) / time);
				}
			}
		}
		return values;
	}

	/**
	 * Calculate the vertical speed values for each point in the given track
	 * @param inTrack track object
	 * @return vertical speed values in a ChartSeries object
	 */
	private static ChartSeries getVertSpeedValues(Track inTrack)
	{
		// Calculate speeds and fill in in values array
		ChartSeries values = new ChartSeries(inTrack.getNumPoints());
		Altitude.Format altFormat = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?Altitude.Format.METRES:Altitude.Format.FEET;
		DataPoint prevPoint = null, currPoint = null, nextPoint = null;
		DataPoint[] points = getDataPoints(inTrack, true); // require that points have altitudes too
		// Loop over collected points
		for (int i=1; i<(points.length-1); i++)
		{
			prevPoint = points[i-1];
			currPoint = points[i];
			nextPoint = points[i+1];
			if (prevPoint != null && currPoint != null && nextPoint != null
				&& nextPoint.getTimestamp().isAfter(currPoint.getTimestamp())
				&& currPoint.getTimestamp().isAfter(prevPoint.getTimestamp()))
			{
				// Calculate average vertical speed between prevPoint and nextPoint
				double vspeed = (nextPoint.getAltitude().getValue(altFormat) - prevPoint.getAltitude().getValue(altFormat))
				 * 1.0 / nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp());
				values.setData(i, vspeed);
			}
		}
		return values;
	}


	/**
	 * Get an array of DataPoints with data for the charts
	 * @param inTrack track object containing points
	 * @param inRequireAltitudes true if only points with altitudes are considered
	 * @return array of points with contiguous non-null elements (<= size) with timestamps
	 */
	private static DataPoint[] getDataPoints(Track inTrack, boolean inRequireAltitudes)
	{
		DataPoint[] points = new DataPoint[inTrack.getNumPoints()];
		DataPoint currPoint = null;
		int pointNum = 0;
		// Loop over all points
		for (int i=0; i<inTrack.getNumPoints(); i++)
		{
			currPoint = inTrack.getPoint(i);
			if (currPoint != null && !currPoint.isWaypoint() && currPoint.hasTimestamp()
				&& (!inRequireAltitudes || currPoint.hasAltitude()))
			{
				points[pointNum] = currPoint;
				pointNum++;
			}
		}
		// Any elements at the end of the array will stay null
		// Also note, chronological order is not checked
		return points;
	}


	/**
	 * Select a file to write for the SVG output
	 * @return selected File object or null if cancelled
	 */
	private File selectSvgFile()
	{
		if (_fileChooser == null)
		{
			_fileChooser = new JFileChooser();
			_fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
			_fileChooser.setFileFilter(new GenericFileFilter("filetype.svg", new String[] {"svg"}));
			_fileChooser.setAcceptAllFileFilterUsed(false);
			// start from directory in config which should be set
			String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
			if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
		}
		boolean chooseAgain = true;
		while (chooseAgain)
		{
			chooseAgain = false;
			if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
			{
				// OK pressed and file chosen
				File file = _fileChooser.getSelectedFile();
				// Check file extension
				if (!file.getName().toLowerCase().endsWith(".svg")) {
					file = new File(file.getAbsolutePath() + ".svg");
				}
				// Check if file exists and if necessary prompt for overwrite
				Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
				if (!file.exists() || (file.canWrite() && JOptionPane.showOptionDialog(_parentFrame,
						I18nManager.getText("dialog.save.overwrite.text"),
						I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
						JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
					== JOptionPane.YES_OPTION))
				{
					return file;
				}
				chooseAgain = true;
			}
		}
		// Cancel pressed so no file selected
		return null;
	}


	/**
	 * @param inNumCharts number of charts to draw
	 * @return array of ints describing position and height of each subchart
	 */
	private static int[] getHeights(int inNumCharts)
	{
		if (inNumCharts <= 1) {return new int[] {0, 100};}
		if (inNumCharts == 2) {return new int[] {25, 75, 0, 25};}
		if (inNumCharts == 3) {return new int[] {40, 60, 20, 20, 0, 20};}
		return new int[] {54, 46, 36, 18, 18, 18, 0, 18};
	}
}
