
import Highcharts from 'highcharts';
import HTreemap from 'highcharts/modules/treemap.js';
import Highcharts3D from 'highcharts/highcharts-3d.js';
import Highstock from 'highcharts/highstock.js';
//import oldie from 'highcharts/oldie.js';
//import cylinder from 'highcharts/cylinder.js';
HTreemap(Highcharts);			// treemap 类型
Highcharts3D(Highcharts);		// 3D 类型

var Highchart = function(){
	
	/**
	  * 图表数据格式化
	  * @param: {Array} list
	  * @param: {Object} opts [standOut(突出最大值)]
	  *	@example1: 
	 
	  		var chartData = formatSeriesList(data, {value:'num'});
	  			input:
				[
					{"name":"高区应急行业","num":3},
					{"name":"0705行业","num":2},
					{"name":"船舶工业行业","num":2},
				]

				output:
				{
					"seriesData":[
						{"0":"上海","1":24.25,"name":"高区应急行业","y":3},
						{"0":"卡拉奇","1":23.5,"name":"0705行业","y":2},
						{"0":"北京","1":21.51,"name":"船舶工业行业","y":2},
					],
					"sum":7
				}

	  *	@example2: 
	  			input:
					var list = [{"name":"高区应急行业","num":16},{"name":"船舶工业行业","num":7}];
					var colors = ['#2CAFFE', '#90ED7D', '#8085E9', '#F15C80', '#E4D354'];
					var series = Highchart.formatSeriesList(list, {value:'num', colors:colors});

				output:{
					"seriesData":[{"name":"高区应急行业","y":16,"color":"#2CAFFE"},{"name":"船舶工业行业","y":7,"color":"#90ED7D"},],
					"sum":28
				}
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2021/12/25
	  * @createtime: 2021/12/25
	  */
	var formatSeriesList = function(list, opts){
		var sdata = [], sum = 0, maxVal = 0, mark = 0, colors = opts.colors || [];
		var len = list.length;
		for(var i=0; i<len; i++){
			var item = list[i], color = colors[i];
			var value = item[opts.value] * 1;
			value > maxVal && (maxVal = value, mark = i);
			var nitem = {name:item[opts.name || 'name'], y:value}
			item.color && (nitem['color'] = item.color);
			color && (nitem['color'] = color);
			sdata.push(nitem);
			sum += value;
		};
		if(opts.standOut){
			sdata[mark].sliced = true;
			sdata[mark].selected = true;
		};
		return {seriesData:sdata, sum:sum};
	};
	

	/**
	  * series数据格式化
	  * @param: {Array} list
	  * @param: {Object} opts [standOut(突出最大值)]
	  *	@example1: 
	  		var chartData = Highchart.seriesDataFormat(list, {datekey:'date', dataReverse:true,});
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2022/12/28
	  * @createtime: 2022/12/28
	  */
	var seriesDataFormat = function(data, opts){
		var names = data.names || [], list = data.list || data.lists, series = [], categories = [],
			maxVal = 0;
		if(names[0] && list){
			var colors = ['#7CB5EC', '#90ED7D', '#F7A35C', '#8085E9', '#F15C80', '#E4D354', '#2B908F', '#F45B5B', '#91E8E1', '#0769CB', '#00ABBD', '#ffd886', "#9F2E61", "#4D670C"];

			var len = names.length;
			for(var i=0; i<len; i++){
				var item = names[i];
				var serie = {name:item.name, data:[], key:item.key, type:data.chartType, color:colors[i]};
				opts && serie.type && (serie.type = opts.type);
				series.push(serie);
			};

			for(var item of list){
				var values = item.values;
				//var datetime = item[opts.datekey || 'dateUnit'];
				//var time = datetime.indexOf(' ') > 0 ? datetime.split(' ')[1] : datetime;
				var timestamp = item['date'];

				categories.push(timestamp);
				for(var serie of series){
					var value = values[serie.key] * 1;
					Math.abs(value) > maxVal && (maxVal = Math.abs(value));
					serie.data.push(opts.dataReverse ? [value, timestamp] : [timestamp, value]);
				};
			};
		};
		return {series:series, categories:categories, maxVal:maxVal}
	};

	
	/**
	  * 递归继承, 新对象在先, 原对象在后, 节省运行效率
	  * @param: {Object} inherit	// 继承者
	  * @param: {Object} give		// 传承者
	  * @param: {Function} call		// 方法回调, 于在在特殊情况自定义
	  *	@example1: var options = reversExtends(option, opts);
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2022/1/12
	  * @createtime: 2022/1/12
	  */
	var reversExtends = function(inherit, give, fn){
		return (function run(main, assist){
			var keys = Object.keys(assist), i = 0;
			return (function loop(){
				var key = keys[i]; i++;
				if(key){
					fn && fn(key, main, assist);
					return typeof main[key] === 'object' ? run(main[key], assist[key]) : (main[key] = assist[key]), loop();
				}else{
					return inherit;
				};
			})();
		})(inherit, give);
	};

	/**
	  * 根据报警级别识别近两条报警线
	  * @param: {Number} level
	  * @param: {Object} value
	  *	@example1: series = discernValidAlarmValue(data.alarm, data.lists, series);
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2022/4/18(周一)
	  * @createtime: 2022/4/18(周一)
	  */
	var discernValidAlarmValue = function(alarms, list, series, direction, opts){
		var xLength = (list || []).length, maxAlarm = 0, opts = opts || {};
		if(alarms && xLength){
			var value = alarms.value;

			// discern
			var levelDist = [
				{color:'red', name:'红色报警线'}, 
				{color:'orange', name:'橙色报警线'}, 
				{color:'yellow', name:'黄色报警线'}, 
				{color:'blue', name:'蓝色报警线'}],
				alarmLine = {}, setAlarmSerie = function(value, name, color){
					// 修改蓝色色值
					(color === 'blue') && (color = '#3BAFFB');
					var sx = list[0].date, ex = list[xLength-1].date;
					var serie = {name:name, type:'spline', data:[{x:sx, y:value}, {x:ex, y:value}], 
						color:color, 
						enableMouseTracking:false,
						legend:false,
						showInLegend:false,
						dashStyle:'ShortDot',
						lineWidth:opts.lineWidth || 1,
						states:{
							inactive:{
								opacity:opts.opacity
							},
						},
						dataLabels:{
							enabled:opts.valEnabled || false,		// 数据值, 2022/11/11(周五) 因多条报警线暂时关闭
							//backgroundColor:'red',
							verticalAlign:'middle',
							padding:0,
							defer:false,
							allowOverlap:true,
							color:color,
							style:{
								textOutline:'none',
							},
						},
						tooltip:{
							//footerFormat:'',
							//pointFormat:'',
							headerFormat:'',
							//nullFormat:'',
						},
						marker:{
							enabled:false
						},
						zIndex:-10,
					};
					series.push(serie);
				};

			/* 智能报警线
			var level = (~~alarms.alarmLevel || levelDist.length+1) - 1;
			var nearLevel = level ? level - 1 : level;
			var alarm = levelDist[level];
			var nearAlarm = levelDist[nearLevel];
			nearAlarm.value = value[nearAlarm.color];
			alarmLine[nearAlarm.color] = nearAlarm;
			if(alarm){
				alarm.value = value[alarm.color];
				alarmLine[alarm.color] = alarm;
			}; */
			
			// 多条报警线
			for(var item of levelDist){
				item.value = value[item.color];
				alarmLine[item.color] = item;
			};

			// add
			for(var key in alarmLine){
				var line = alarmLine[key];
				line.value > maxAlarm && (maxAlarm = line.value);
				setAlarmSerie(line.value, line.name, line.color);
				direction && setAlarmSerie(0-line.value, line.name, line.color);
			};
		};
		return {series, maxAlarm};
	};

	var addAlarmLine = function(alarms, list, series, direction){
		var xLength = (list || []).length;
		if(alarms && xLength){
			var value = alarms.value;
			// discern
			var levelDist = [
				{color:'red', name:'红色报警线'}, 
				{color:'orange', name:'橙色报警线'}, 
				{color:'yellow', name:'黄色报警线'}, 
				{color:'blue', name:'蓝色报警线'}],
				alarmLine = {}, setAlarmSerie = function(value, name, color){
					var serie = {name:name, type:'spline', data:[{x:0, y:value}, {x:xLength, y:value}],				color:color, 
						//enableMouseTracking:false,
						legend:false,
						showInLegend:false,
						dashStyle:'ShortDot',
						states:{
							inactive:{
								opacity:1
							},
						},
					};
					series.push(serie);
				};

			for(var item of levelDist){
				var value = alarms[item.color] * 1;
				if(value){
					setAlarmSerie(value, item.name, item.color);
					direction && setAlarmSerie(0-value, item.name, item.color);
				};
			};
		};
		return series;
	};

	var template = {
		pie: function(el, list, opts){
			var chartConfig = opts.chartConfig || {};
			var chartData = {}, seriesData = [];
			if(!opts.isSeriesData){
				// opts.formatLimit = {datekey:'date'}
				chartData = formatSeriesList(list, {value:'num'});
				seriesData = chartData.seriesData;
			};

			var options = {
				chart: {
					backgroundColor:'transparent',
				},
				title: {
					floating:true,
					text: '总数<br/>'+chartData.sum,
					verticalAlign: 'middle',
					y:22,
					floating: true,
					style:{
						color:'#00f6ff',
					}
				},
				tooltip: {
					pointFormat: '{seriesData.name}: <b>{point.percentage:.1f}%</b>'
				},
				plotOptions: {
					pie: {
						allowPointSelect: true,
						borderWidth: 0,
						minSize:130,
						cursor: 'pointer',
						dataLabels: {
							enabled: true,
							distance:10,
							format: '<b>{point.name}</b>: {point.percentage:.1f} %',
							style: {
								color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
							}
						},
					}
				},
				credits: {
					enabled: false
				},
				series: [{
					type: 'pie',
					innerSize: '70%',
					name: '设备数量',
					data: seriesData
				}]
			};

			options = reversExtends(options, chartConfig, opts.callback);

			return new Highcharts.chart(el, options, function(c) { // 图表初始化完毕后的会掉函数
				opts.chartCallback && opts.chartCallback(c);
			});
		}, 
		
		/**
		  * 浮动菜单容器
		  * @param: {Dom} el 
		  * @param: {Object} data
		  * @param: {Object} opts	{chartConfig:{}, callback:Function}
		  *	@example1:
		  * @return: 
		  * @author: Kimber
		  * @updatetime: 2022/1/11
		  * @createtime: 2022/1/11
		  */
		high: function(el, data, opts){
			var list = data.list;
			data.chartType = data.range === 'month' ? 'line' : 'column';
			var chartConfig = opts.chartConfig || {};
			
			var chartData, categories = [], series = [], maxVal = null;
			if(opts.isSeriesData){
				
			}else{
				chartData = seriesDataFormat(data, {});
				categories = chartData.categories;
				series = chartData.series;
			};

			// add alarm line
			var alarmData = discernValidAlarmValue(data.alarm, data.lists, series, opts.warningLine);
			//series = addAlarmLine(data.alarm, data.lists, series, opts.warningLine);

			// 识别最大值
			var maxVal = chartData && chartData.maxVal > alarmData.maxAlarm ? chartData.maxVal : alarmData.maxAlarm;
			var option = {
				chart: {
					type: data.chartType,
					backgroundColor:'transparent',
					//marginTop:30,
					marginBottom:22,
					marginLeft:30,
				},
				title: {
					text: ''
				},
				subtitle: {
					text: ''
				},
				xAxis: {
					type: 'datetime' || 'category',
					labels: {
						rotation:0,  // 设置轴标签旋转角度
						style:{
							color:'#fff'
						},
						y:15,
					},
					categories: categories[0] && categories,
					lineWidth:0,
					//lineColor:'#ff0000',
					gridLineColor:'#aaa',
					tickLength:0,		// 刻度线

					dateTimeLabelFormats: {
						millisecond: '%H:%M:%S.%L',
						second: '%H:%M:%S',
						minute: '%H:%M',
						hour: '%H:%M',
						day: '%m-%d',
						week: '%m-%d',
						month: '%Y-%m',
						year: '%Y'
					}
				},
				yAxis: {
					title: {
						text: ''
					},
					labels:{
						style:{
							color:'#fff'
						},
						x:-6,
					},
					gridLineColor:'#0F5680',
					//minorGridLineWidth: 5,
					//gridLineWidth: 5,
					max:opts.maxValDev ? maxVal + maxVal * opts.maxValDev : null,
				},
				plotOptions: {
					column: {
						borderWidth: 0,
						//y:50,
						//itemMarginTop:50,
					},
					bar:{
						borderWidth: 0,
					},
				},
				legend: {
					enabled: series.length > 1 ? true : false,
					// 图例定位
					layout: 'horizontal',				// 水平布局:“horizontal”, 垂直布局:“vertical”
					floating: false,					// 图列是否浮动
					align: 'right',
					
					// 图例容器
					//width:'100%',		// number	|| String
					padding:2,			// 内边距
					margin:2,
					borderRadius:5,
					//borderWidth:1,
					verticalAlign: 'top',

					// 图例项
					//itemWidth:120,		// 宽度
					itemDistance:10,	// 间距	20
					y:-10,
					itemMarginTop:2,
					itemStyle:{color:'#fff',},
					itemHoverStyle:{color:'#fff',},
				},
				credits: {
					enabled: false
				},
				tooltip: {
					/* formatter: function (e) {
						return this.series.name + "："+ this.key +'<br/>'+ this.y.toFixed(3)+' ' + data.unit;
					}, */
					pointFormat: '{series.name}：{point.y} ' + data.unit,
					dateTimeLabelFormats: {
						millisecond: '%H:%M:%S.%L',
						second: '%H:%M:%S',
						minute: '%m-%d %H:%M',
						hour: '%m-%d %H:%M',
						day: '%m-%d %H:%M',
						week: '%m-%d %H:%M',
						month: '%Y-%m',
						year: '%Y'
					}
				},
				series: series
			};

			Highcharts.setOptions({
				global: {
					useUTC: false
				},
			});

			var options;
			if(opts.isSeriesData){
				options = reversExtends(option, chartConfig, opts.callback);
				if(opts.type === "t_10"){
					delete options.legend;
					delete options.xAxis;
					delete options.yAxis;
				};
			}else{
				options = reversExtends(option, chartConfig, opts.callback);
			};
			
			return new Highcharts.chart(el, options);
		},

		rich: function(el, list, opts){
			var chartConfig = opts.chartConfig || {};
			var chartData, categories = [], series = [], maxVal = null, unit = opts.danwei || '';
			if(opts.isSeriesData){
				
			}else{
				chartData = seriesDataFormat(list, {datekey:'date'});
				categories = chartData.categories;
				series = chartData.series;
			};

			var option = {
				chart: {
					//type: '',
					backgroundColor:'transparent',
					//marginTop:30,
					//marginBottom:30,
					//marginLeft:30,
					zoomType: 'x',		// xy
				},
				title: {
					text: ''
				},
				subtitle: {
					text: ''
				},
				tooltip:{
					enabled:false,
					borderWidth:10,
				},
				xAxis: {
					type: 'datetime',
					labels: {
						rotation:0,  // 设置轴标签旋转角度
						style:{
							color:'#fff'
						},
						//y:15,
					},
					categories: categories[0] && categories,
					lineWidth:0,
					//lineColor:'#ff0000',
					gridLineColor:'#aaa',
					
					dateTimeLabelFormats: {
						millisecond: '%H:%M:%S.%L',
						second: '%H:%M:%S',
						minute: '%H:%M',
						hour: '%H:%M',
						day: '%m-%d',
						week: '%m-%d',
						month: '%Y-%m',
						year: '%Y'
					}
				},
				yAxis: {
					title: {
						text: ''
					},
					labels:{
						style:{
							color:'#fff'
						},
						x:-6,
					},
					gridLineColor:'#aaa',
					max:null,
				},
				plotOptions: {
					column: {
						borderWidth: 0,
						//y:50,
						//itemMarginTop:50,
					},
					bar:{
						borderWidth: 0,
					},
				},
				tooltip: {
					// {point.y:.4f}	// 保留4位小数
					//headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
					pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}:</td>' +
					'<td style="padding:0"><b>{point.y}'+unit+'</b> </td></tr>',
					footerFormat: '</table>',
					shared: true,
					useHTML: true,
					dateTimeLabelFormats: {
						millisecond: '%H:%M:%S.%L',
						second: '%H:%M:%S',
						minute: '%H:%M',
						hour: '%H:%M',
						day: '%m-%d %H时',
						week: '%m-%d',
						month: '%Y-%m',
						year: '%Y'
					}
				},
				legend: {
					enabled: series.length > 1 ? true : false,
					// 图例定位
					layout: 'horizontal',				// 水平布局:“horizontal”, 垂直布局:“vertical”
					floating: false,					// 图列是否浮动
					align: 'right',
					
					// 图例容器
					//width:'100%',		// number	|| String
					padding:2,			// 内边距
					margin:2,
					borderRadius:5,
					//borderWidth:1,
					verticalAlign: 'top',

					// 图例项
					//itemWidth:120,		// 宽度
					itemDistance:10,	// 间距	20
					y:-10,
					itemMarginTop:2,
					itemStyle:{},
					itemHoverStyle:{},
				},
				credits: {
					enabled: false
				},
				series: series
			};

			Highcharts.setOptions({
				global: {
					useUTC: false
				},
				lang:{
					resetZoom:'重置缩放比例',
				},
			});

			var options;
			if(opts.isSeriesData){
				options = reversExtends(option, chartConfig, opts.callback);
			}else{
				options = reversExtends(option, chartConfig, opts.callback);
			};
			return new Highcharts.chart(el, options, function(c) { // 图表初始化完毕后的会掉函数
				opts.chartCallback && opts.chartCallback(c);
			});
		},

		/**
		  * 注释标题
		  * @param: {Dom} el 
		  * @param: {Object} data
		  * @param: {Object} opts	{chartConfig:{}, callback:Function}
		  *	@example1:
		  		var opts = {
					chartConfig:{
						chart:{
							type: 'column',
							marginTop:0,
							marginLeft:25,
							marginBottom:0,
							spacingLeft:0,
							spacingBottom:-5,
						},
						series: [{
							name: '',
							tooltip: {
								valueDecimals: 2
							},
						}]
					},
					notExtendsOptions:false,
				};
				Highchart.template.stock(wrap32, data, opts);
		  * @return: 
		  * @version: V0.1
		  * @author: Kimber
		  * @updatetime: 2024/7/12(周五)
		  * @createtime: 2024/7/12(周五)
		  */
		stock: function(el, data, opts){
			var chartData = formatSeriesList(data, {value:'num'});
			var chartConfig = opts.chartConfig || {};

			var option = {
				chart:{
					backgroundColor:'transparent',
				},
				rangeSelector: {		// 关闭选择列表
					enabled: false
				},
				title: {
					//text: 'AAPL Stock Price'
				},
				xAxis: {
					type: 'datetime',
					max:10,
					labels: {
						rotation:0,  // 设置轴标签旋转角度
						style:{
							color:'#ffffff'
						},
						y:2,
						enabled:false,
					},

					lineWidth:0,
					gridLineColor:'#aaa',
					tickLength:0,		// 刻度线
					alignTicks:false,
				},
				yAxis: {	
					title: {
						text: ''
					},
					labels:{
						style:{
							color:'#fff'
						},
						x:-5,
					},
					gridLineColor:'#00C4FE',
					opposite: false,
					offset: 0,
					lineWidth: 1,
					lineColor:'#00C4FE'
				},
				plotOptions: {
					column: {
						borderWidth: 0,
						//y:50,
						//itemMarginTop:50,
					},
					bar:{
						borderWidth: 0,
					},
				},
				navigator : {
					enabled : false
				},
				scrollbar : {
					enabled : true,
					barBackgroundColor: '#00C4FE',
					barBorderRadius: 7,
					barBorderWidth: 0,
					buttonBackgroundColor: '#00C4FE',
					buttonBorderWidth: 0,
					buttonBorderRadius: 7,
					trackBackgroundColor: 'rgba(0,28,57, .5)',
					trackBorderWidth: 1,
					trackBorderRadius: 5,
					trackBorderColor: '#65D6F7',
					height:12,
				},
				credits: {
					enabled: false
				},
				legend: {
				},
				tooltip: {
					formatter: function (e) {
						return this.series.name + ""+ this.key +'<br/>'+ this.y.toFixed(3);
					},
					//pointFormat: '{point.y} ',
				},
				series: [{
					name: '',
					data: chartData.seriesData,
					tooltip: {
						valueDecimals: 2
					},
					dataLabels: {	// 柱内显示文字内容
						enabled: true,
						rotation: 90,
						color: '#FFFFFF',
						align: 'top',
						formatter: function(e){
							return this.key + ' ' + this.y;
						},
						y:10,
						style:{
							fontSize:10,
							textShadow:'none',
						},
					}
				}]
			};
	
			var options;
			if(opts.isSeriesData){
				options = reversExtends(option, chartConfig, opts.callback);
			}else{
				options = reversExtends(option, chartConfig, opts.callback);
			};
			
			Highstock.setOptions({
				global: {
					useUTC: false
				},
			});
			return new Highstock.stockChart(el, options);
		},
	};

	var getRandomColor = function(random){
		if(random === true){
			return 'rgb(' + [Math.round(Math.random() * 160), Math.round(Math.random() * 160), Math.round(Math.random() * 160)].join(',') + ')';
		}else{
			var colors = ['#7CB5EC', '#434348', '#90ED7D', '#F7A35C', '#8085E9', '#F15C80', '#E4D354', '#2B908F', '#F45B5B', '#91E8E1', '#0769CB', '#00ABBD', '#ffd886', "#9F2E61", "#4D670C"];
			if(typeof random === 'number'){
				return colors[~~random];
			}else{
				return colors[~~(Math.random()*colors.length)];
			};
		};
	};

	return {
		template:template, getRandomColor:getRandomColor, seriesDataFormat, formatSeriesList
	}
};

export var Highchart = Highchart();
