package com.ht.ui.monitor;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Screen;
import javafx.util.StringConverter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ht.data.RealTimeDataManager;
import com.ht.data.TagInfoManager;
import com.ht.data.listener.IDataListener;
import com.ht.tags.model.tag.TagVar;
import com.ht.ui.MainApplication;

public class RealTimeLineChartViewer extends Group {
	private static final Logger log = LoggerFactory.getLogger(RealTimeLineChartViewer.class);

	private VBox mainPannel = new VBox(3);
	private Map<String, XYChart.Series<Number, Number>> seriesMap = new HashMap<String, XYChart.Series<Number,Number>>();
	private NumberAxis xAxis;
	private NumberAxis yAxis;
	private LineChart<Number, Number> chart;

	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d HH:mm:ss");
	private DecimalFormat decimalFormat = new DecimalFormat("0.00");


	/**
	 * 显示变量实时曲线
	 * @param title 标题
	 * @param tagVarName 变量名
	 * @param updatePeriod 图像变化周期， 单位为毫秒，图像在固定的时间周期在向左平移
	 */
	public RealTimeLineChartViewer(final String title, final int updatePeriod, final String ...tagVarName) {

		mainPannel.getStyleClass().addAll("window", "dataCurve", "monitor");
		mainPannel.setAlignment(Pos.TOP_CENTER);
		mainPannel.setSpacing(3);
		getChildren().add(mainPannel);
		
		Rectangle2D rect = Screen.getPrimary().getVisualBounds();
		double maxHeight = rect.getHeight() - 170;
		double width = rect.getWidth() * 0.618;
		mainPannel.setPrefSize(width, maxHeight);
		mainPannel.setMaxSize(width, maxHeight);
		// block mouse clicks
		setOnMouseClicked(new EventHandler<MouseEvent>() {

			@Override
			public void handle(MouseEvent t) {
				t.consume();
			}
		});

		createChart(title, updatePeriod, tagVarName);

		configDataChangeListener(updatePeriod, tagVarName);


	}

	private void configDataChangeListener(final int updatePeriod, final String ...tagVarName) {

		final IDataListener dataListener = new IDataListener() {
			private Set<String> set = new HashSet<String>();
			private Double lastValue = null;
			
			{
				for (String s : tagVarName) {
					set.add(s);
				}
			}

			@Override
			public Set<String> getDataVarNames() {
				return set;
			}

			@Override
			public void dataChanged(String ...varNames) {
				for (String varName : varNames) {
					
					Object obj = RealTimeDataManager.INSTANCE.getVarValue(varName);
					
					XYChart.Series<Number, Number> series = seriesMap.get(varName);
					if (obj instanceof Number && series != null) {

						Date datetime = new Date();
						long l = datetime.getTime();
						series.getData().add( new XYChart.Data<Number, Number>(l / updatePeriod, (Number) obj));
						xAxis.setLowerBound(l / updatePeriod - 50);
						xAxis.setUpperBound(l / updatePeriod + 5);

						lastValue = ((Number) obj).doubleValue();
					}
				}
			}
		};

		RealTimeDataManager.INSTANCE.registDataChangeListener(dataListener);
		visibleProperty().addListener(new ChangeListener<Boolean>() {
			@Override
			public void changed(ObservableValue<? extends Boolean> observable,
					Boolean oldValue, Boolean newValue) {
				if (newValue != null && !newValue) {
					RealTimeDataManager.INSTANCE
							.unregistDataChangeListener(dataListener);
				}
			}
		});

		parentProperty().addListener(new ChangeListener<Parent>() {
			@Override
			public void changed(ObservableValue<? extends Parent> observable,
					Parent oldValue, Parent newValue) {
				if (newValue == null) {
					RealTimeDataManager.INSTANCE
							.unregistDataChangeListener(dataListener);
				}
			}
		});
	}

	private void createChart(final String title, final int updatePeriod, final String ...tagVarName) {
		xAxis = new NumberAxis();
		xAxis.setTickUnit(5);
		xAxis.setMinorTickVisible(false);
		xAxis.setAutoRanging(false);
		xAxis.setForceZeroInRange(false);
		xAxis.setTickLabelFormatter(new StringConverter<Number>() {

			private SimpleDateFormat sdf = new SimpleDateFormat("  MM-dd\nHH:mm:ss");

			@Override
			public Number fromString(String string) {
				return 20;
			}

			@Override
			public String toString(Number object) {
				// return object.toString();
				return sdf.format(new Date(object.longValue() * updatePeriod));
			}
		});
		
		yAxis = new NumberAxis();
		yAxis.setForceZeroInRange(false);
		yAxis.setAutoRanging(false);
		yAxis.setAutoRanging(true);

		chart = new LineChart<Number, Number>(xAxis, yAxis);
		chart.setMinHeight(mainPannel.getMaxHeight());
		chart.setCreateSymbols(false);
		chart.setAnimated(false);
		//chart.setLegendVisible(false);
		chart.setTitle(title);
		mainPannel.getChildren().addAll(chart);
		// yAxis.setLabel("Y Axis");

		// xAxis.setLabel("X Axis");

		// add starting data
		for (String name : tagVarName) {
			XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>();
			
			Map<String, TagVar> tagVarNameMap = TagInfoManager.INSTANCE.getTagVarNameMap();
			if (tagVarNameMap != null) {
				
				TagVar tagVar = tagVarNameMap.get(name);
				if (tagVar == null) {
					series.setName(name);
				} else {
					series.setName(tagVar.getName());
				}
			} else {
				series.setName(name);
			}
			seriesMap.put(name, series);
			chart.getData().add(series);
		}
//		series = new XYChart.Series<Number, Number>();
//		series.setName(title);
//		chart.getData().add(series);
	}

	public static class VarTableModel {
		private StringProperty datetime;
		private StringProperty sumValue;
		private StringProperty changeValue;

		private VarTableModel(String datetime, String sumValue,
				String changeValue) {
			this.datetime = new SimpleStringProperty(datetime);
			this.sumValue = new SimpleStringProperty(sumValue);
			this.changeValue = new SimpleStringProperty(changeValue);
		}

		public StringProperty datetimeProperty() {
			return datetime;
		}

		public StringProperty sumValueProperty() {
			return sumValue;
		}

		public StringProperty changeValueProperty() {
			return changeValue;
		}
	}

	/**
	 * 显示变量实时曲线
	 * @param title 标题
	 * @param tagVarName 变量名
	 * @param updatePeriod 图像变化周期， 单位为毫秒，图像在固定的时间周期在向左平移
	 */
	public static void showWindow(final String title, final int updatePeriod, final String ...tagVarName) {
		if (tagVarName.length == 0) {
			return;
		}
		log.info("显示实时曲线: {}", tagVarName);
		
		Platform.runLater(new Runnable() {

			public void run() {
				MainApplication.getMainApp().showModalMessage(
						new RealTimeLineChartViewer(title, updatePeriod, tagVarName));
			}
		});
	}

}
