<template>
	<div></div>
</template>

<script>
module.exports = {
	props: {
		width: {
			default: 600,
			type: Number
		},
		height: {
			default: 480,
			type: Number
		},
		dtRange: {
			default: {},
			type: Object,
			required: true,
			validator(value) {
				let keys = Object.keys(value);
				return keys.includes("max") && keys.includes("min");
			}
		},
		title: {
			default: "",
			type: String,
		},
		datas: {
			default: [],
			type: Array,
			required: true,
		},
		barHeight: {
			default: 20,
			type: Number
		},
		fontSize: {
			default: 20,
			type: Number
		},
		topPadding: {
			default: 80,
			type: Number
		},
		sidePadding: {
			default: 160,
			type: Number
		},
		timeScale: {
			default: { unit: 'day', interval: 1 },
			type: Object
		}
	},
	data: () => {
		return {
			gantt_id: null,
		}
	},
	mounted () {
		this.comFnReDraw();
	},
	/*
	watch: {
		"ganttId": {
			immediate: true,
			handler (nv, ov) {
				if (nv) {}
			}
		}
	},
	*/
	computed: {
		ganttId () {
			return "gantt_" + this._uid;
		},
		gap () {
			return this.barHeight * 1.5;
		},
		categories () {
			return this.datas.reduce((pv, cv) => {
				pv.push(cv["ItemName"]);
				return pv;
			}, []);
		},
		uniCategories () {
			return this.categories.uniquelize();
		},
		groupDatas () {
			var obj = this.uniCategories.reduce((pv, cv, i) => ({ ...pv, [cv]: i }), {});
			return this.datas.sort((a, b) => obj[a["ItemName"]] - obj[b["ItemName"]]);
		},
		colorScale () {
			return d3.scaleLinear()
						.domain([0, 4])
						.range(["#1a237e", "#bf360c"])
						.interpolate(d3.interpolateHcl);
		},
		dateFormat () { 
			return d3.time.format("%Y-%m-%d %H:%M");
		},
		timeScale () {
			return d3.scaleTime()
						.domain([Date.parse(this.dtRange.min), Date.parse(this.dtRange.max)])
						.range([0, (this.width - this.sidePadding)]);
		},
		linearScale () {
			return d3.scaleLinear()
						.domain([0, this.categories.length])
						.range([0, (this.height - this.topPadding)]);
		},
		xAxis () {
			return d3.axisTop(this.timeScale)
						.ticks(d3.timeDay, 1)
						.tickSize(this.height - (this.topPadding + this.fontSize), 0, 0)
						.tickFormat(d3.timeFormat("%d"));
		},
	},
	methods: {
		comFnReDraw () {
			
			var self = this;
			const w = this.width;
			const h = this.height;
			const px = this.fontSize;
			const gap = this.gap;
			const sidePad = this.sidePadding;
			const topPad = this.topPadding;
			
			const svg = d3.select(this.$el)
							.attr("id", this.ganttId)
							.append("svg")
							.attr("width", "100%")
							.attr("height", "100%")
							.attr("preserveAspectRatio", "xMaxYMax meet")
							.attr("viewBox", `0 0 ${w} ${h}`)
							.attr("class", "com-gantt-svg");
			
			const draw_title = () => {
				if (!this.title) 
					return;
				svg.append("text")
					.text(this.title)
					.attr("x", w / 2)
					.attr("y", 25)
					.attr("text-anchor", "middle")
					.attr("font-size", px * 1.5)
					.attr("fill", "#009FFC");
			};
			// X 軸
			const draw_axisX = (x) => {
				svg.append("g")
					.attr("class", "gantt-x")
					.attr("transform", `translate(${sidePad}, ${h - (px * 1.5)})`)
					.call(x || this.xAxis)
					.selectAll("text")
					.style("text-anchor", "middle")
					.attr("fill", "#333")
					.attr("stroke", "none")
					.attr("font-size", px * 0.85)
					.attr("dy", -4);
			};
			
			const draw_bgColor = () => {
				svg.append("g")
					.selectAll("rect")
					.data(this.groupDatas)
					.enter()
					.append("rect")
					.attr("x", 0)
					.attr("y", function (d, i) {
						return i * gap + topPad - 2;
					})
					.attr("width", w)
					.attr("height", gap)
					.attr("stroke", "none")
					.attr("fill", function (d) {
						var i = self.uniCategories.findIndex(type => type == d["ItemName"]);
						return d3.rgb(self.colorScale(i % 5));
					})
					.attr("opacity", 0.2);
			};
			
			const draw_chart = () => {
				const time_scale = this.timeScale;
				const rectangles = svg.append("g")
										.selectAll("rect")
										.data(this.groupDatas)
										.enter();
										
				rectangles.append("rect")
							.attr("class", "task")
							.attr("rx", 3)
							.attr("ry", 3)
							.attr("x", function (d) {
								return time_scale(Date.parse(d.StartTime)) + sidePad;
							})
							.attr("y", function (d, i) {
								return i * gap + topPad;
							})
							.attr("width", function (d) {
								return Math.max(time_scale(Date.parse(d.EndTime)) - time_scale(Date.parse(d.StartTime)), 0);
							})
							.attr("height", self.barHeight)
							.attr("stroke", "none")
							.attr("fill", function (d) {
								var i = self.uniCategories.findIndex(type => type == d["ItemName"]);
								return d3.rgb(self.colorScale(i % 5)).darker();
							}).on("click", (data) => {
								this.$emit("task_click", data);
							});
			};
			
			const draw_label = () => {
				var numOccurances = new Array();
				var acc_gap = 0;

				for (var i = 0; i < self.uniCategories.length; i++) {
					numOccurances[i] = [self.uniCategories[i], self.comFnGetCount(self.uniCategories[i], self.categories)];
				}

				svg.append("g")
					.selectAll("text")
					.data(numOccurances)
					.enter()
					.append("text")
					.text(d => d[0])
					.attr("x", 10)
					.attr("y", function (d, i) {
						// console.log(d);
						if (i > 0) {
							for (var j = 0; j < i; j++) {
								acc_gap += numOccurances[i - 1][1];
								return d[1] * gap / 2 + acc_gap * gap + topPad;
							}
						} else {
							return d[1] * gap / 2 + topPad;
						}
					})
					.attr("font-size", px)
					.attr("text-anchor", "start")
					.attr("text-height", px)
					.attr("fill", function (d) {
						var i = self.uniCategories.findIndex(type => type == d[0]);
						return d3.rgb(self.colorScale(i % 5)).darker();
					});
			};
			
			draw_title();
			draw_axisX();
			draw_chart();
			draw_bgColor();
			draw_label();
			
			svg.call(d3.zoom()
				.scaleExtent([1, 4])
				.translateExtent([[0, 0], [w - sidePad, h]])
				.on("zoom", () => {
				
				let time_scale = d3.event.transform.rescaleX(this.timeScale);
				// let liner_scale = d3.event.transform.rescaleY(this.linearScale);
				
				svg.select(".gantt-x")
					.call( this.xAxis.scale(time_scale))
					.selectAll("text")
					.style("text-anchor", "middle")
					.attr("fill", "#333")
					.attr("stroke", "none")
					.attr("font-size", px * 0.85)
					.attr("dy", -4);
				
				svg.selectAll(".task")
					.attr("x", function (d) {
						return Math.max(time_scale(Date.parse(d.StartTime)) + sidePad, sidePad);
					})
					// .attr("y", function (d, i) {
					// 	console.log(liner_scale(i));
					// 	return Math.max(liner_scale(i) + topPad, topPad);
					// })
					.attr("width", function (d) {
						let _x = time_scale(Date.parse(d.StartTime)) + sidePad;
						let _w = Math.max(time_scale(Date.parse(d.EndTime)) - time_scale(Date.parse(d.StartTime)), 0);
						
						if (_x >= sidePad) 
							return _w; 
						
						return Math.max(_w - (sidePad - _x), 0);
					});
			}));
		},
		comFnGetCounts (arr) {
			var i = arr.length, obj = {};
			while (i) {obj[arr[--i]] = (obj[arr[i]] || 0) + 1;}
			return obj;
		},
		comFnGetCount (word, arr) {
			return this.comFnGetCounts(arr)[word] || 0;
		}
	}
}
</script>

<style>
.gantt-x .tick {
    stroke: lightgrey;
    opacity: 0.3;
    shape-rendering: crispEdges;
}
.gantt-x .tick text {
	/*font-size: 0.625em;*/
}
</style>