function random(n){
	return Math.floor(Math.random()*n);
}

$(document).ready(function (){
	$.post("api/fetch_etl", function(s){
		console.log(s);
	})
	.done(function(data) {
		$('.templates').empty();
		$etls = JSON.parse(data);
		$.each($etls, function(index, item)
		{
			$('.templates').append("<option>"+item+"</option>");
		});
	})
	.fail(function() {
		alert( "template list fetch fail" );
	})
});

class TypeBase {
	attrs = {
		name: "",
		type: "",
		text: "텍스트",
		datasrc: "데이터index",
		x: 100,
		y: 100,
		width: 300,
		height: 300,
		color: 'black',
		borderColor: 'transparent',
		backgroundColor: 'transparent',
		align: "center",
		verticalAlign: "middle",
		zIndex: 1,
		fontName: "NanumSquareB.ttf",
		fontSize: 12
	}
	setAttrs(attrs){
		for(var i in attrs) {
			this.attrs[i] = attrs[i];
		}
	}
	_buildRandomName(){
		this.attrs.name = this.attrs.type + random(65536).toString(16).toUpperCase();
	}
	constructor(data) {		
		for(var i in data) {
			this.attrs[i] = data[i];
		}
		//if (!this.attrs.name)
			//this._buildRandomName();
	}
}
class ItemLabel extends TypeBase {
	constructor(data){
		data.type = "Label";
		super(data);
	}
}
class ItemImage extends TypeBase {
	constructor(data){
		data.type = "Image";
		//data.opacity = 0.5;
		if (!data.imageUrl)
			data.imageUrl = "https://picsum.photos/200/300";	
		super(data);
	}
}

var EditorApp = Backbone.View.extend({
	el: 'body',
	list: [],
	events: {
		'click .new-template-btn': 'newtemplateclick',
		'click .save-btn': 'saveclick',
		'click .new-item-btn': 'newitemclick',
		'click .delete-item-btn': 'deleteitemclick',
		'click .new-template-btn': 'newtemplateclick',
		'change .property-input': 'propertychange',
		'change .config-props': 'configchange',
		'click .src-btn': 'srcclick',
		'click .data-btn': 'dataclick',
		'click .save-template-btn': 'savejsonclick',
		'click .render-btn': 'renderclick',
		'click .to-top-btn': 'totopclick',
		'click .to-bottom-btn': 'tobottomclick',
		'keydown #canvas': 'canvaskeydown',
		'focus input': 'inputfocus',
		'blur input': 'inputblur',
		'click .delete-btn': 'deletetemplate',
		'click #inch4': 'inch4click',
		'click #inch7': 'inch7click',
		'click #inch7vertical': 'inch7verticalclick',
		'click #inch11': 'inch11click'
	},
	canvaskeydown: function(e){
		if (!this.selected) 
			return;
		console.log(e.keyCode);
		e.stopPropagation();
		e.preventDefault();
		var item = this.selected.item;
		switch(e.keyCode) {
			case 37://L
				item.attrs.x -= 1;
				break;
			case 38://T
				item.attrs.y -= 1;
				break;
			case 39://R
				item.attrs.x += 1;
				break;
			case 40://B
				item.attrs.y += 1;
				break;
			case 46: //DEL
				this.deleteitemclick(e);
				return;
			case 45: //INSERT
				this.newitemclick(e);
				return;
			default: return;			
		}
		this.render();
		this.selected = this.findView(item);
		this.buildPropEditor(this.selected.item);		
		this.selectView(this.selected);
	},
	findView: function(item)
	{
		for(var i in this.layer.children) {
			var view = this.layer.children[i];
			if(view.item == item)
				return view;
		}
		return null;
	},
	deleteitemclick: function(e){
		if(!confirm('선택된 아이템을 삭제합니다.'))
			return;
		this.removeItem(this.selected.item);
		this.selected = null;
		this.render();
	},
	newtemplateclick: function(){
		this.checkDirty();
		this.load(this.initialData);
	},
	inputfocus: function(){
		this.editing = true;
		console.log('focus');
	},
	inputblur: function(){
		//this.editing = false;
		console.log('blur');
	},
	deletetemplate: function(){
		$template_name = $("select[name=templates]").val();
		
		if(!confirm($template_name + " 템플릿을 삭제합니다."))
			return;
		
		$.post("api/delete", {
			title: $template_name
		}, function(s){
			console.log(s);
			alert("삭제되었습니다.");
			location.reload();
		});
	},
	inch4click: function(){
		document.getElementById("iWidth").value = '400';
		document.getElementById("iHeight").value = '300';
		
		this.config.width = this.$('#iWidth').val()*1;
		this.config.height = this.$('#iHeight').val()*1;
		this.find('_sysborder').width(this.config.width);
		this.find('_sysborder').height(this.config.height);
		console.log(this.config);
		this.layer.draw();
	},
	inch7click: function(){
		document.getElementById("iWidth").value = '640';
		document.getElementById("iHeight").value = '384';
		
		this.config.width = this.$('#iWidth').val()*1;
		this.config.height = this.$('#iHeight').val()*1;
		this.find('_sysborder').width(this.config.width);
		this.find('_sysborder').height(this.config.height);
		console.log(this.config);
		this.layer.draw();
	},
	inch7verticalclick: function(){
		document.getElementById("iWidth").value = '384';
		document.getElementById("iHeight").value = '640';
		
		this.config.width = this.$('#iWidth').val()*1;
		this.config.height = this.$('#iHeight').val()*1;
		this.find('_sysborder').width(this.config.width);
		this.find('_sysborder').height(this.config.height);
		console.log(this.config);
		this.layer.draw();
	},
	inch11click: function(){
		document.getElementById("iWidth").value = '640';
		document.getElementById("iHeight").value = '960';
		
		this.config.width = this.$('#iWidth').val()*1;
		this.config.height = this.$('#iHeight').val()*1;
		this.find('_sysborder').width(this.config.width);
		this.find('_sysborder').height(this.config.height);
		console.log(this.config);
		this.layer.draw();
	},
	removeItem: function(item) {
		var i = this.list.indexOf(item);
		this.list.splice(i, 1);		
	},	
	totopclick: function(){
		if (!this.selected)
			return
		this.removeItem(this.selected.item);
		this.list.push(this.selected.item);
		this.render();
	},
	tobottomclick: function(){
		if (!this.selected)
			return
		this.removeItem(this.selected.item);
		this.list.unshift(this.selected.item);
		this.render();
		//this.selected.moveToBottom();
		//this.layer.draw();
	},
	renderclick: function(){
		var me = this;
		var template = me.buildResult();
		console.log(template);
		
		
		var outfn = 'test'+Date.now()+'.png';

		$.post("api/render", {
			template: JSON.stringify(template),
			data: JSON.stringify(sampleData),
			dataJson: 'xxx',//JSON.stringify(sampleData),
			outputfilename: outfn,
		}, function(s){
			window.open('result/'+outfn);
		}, 'json').fail(function(e){
			console.log(e);
			console.log(e.responseText);
			alert(e.responseText);
		});
	},
	savejsonclick: function(){
		var me = this;
		try {
			var $el = this.$('#json-editor').find('textarea');
			me.load(JSON.parse($el.val())); 
			$el.attr('dirty', false);
			this.$('#json-editor').modal('hide');
		}catch(e) {
			alert(e);
			console.log(e);
			throw e;
		}
	},
	dataclick: function(){
		var me = this;
		var $el = this.$('#data-editor').find('textarea');
		if(localStorage.sampleData)
			$el.val(localStorage.sampleData);
		else
			$el.val(JSON.stringify(sampleData));
		this.$('#data-editor').modal('show');
	},
	srcclick: function(){
		var me = this;
		var json = JSON.stringify(this.buildResult(), null, 2);
		var $el = this.$('#json-editor').find('textarea');
		$el.val(json).attr('dirty', true);
		
		this.$('#json-editor').modal('show');		
	},
	initialData: {
		width: 800,
		height: 500,
		title: "noname",
		rotate: 0,
		items: [],
	},
	config: {
		width: 800,
		height: 500,
		title: "noname",
		rotate: 0
	},
	configchange: function(){
		this.config.width = this.$('#iWidth').val()*1;
		this.config.height = this.$('#iHeight').val()*1;
		this.config.rotate = this.$('#iRotate').val()*1;
		this.config.title = this.$('#sTitle').val();		
		this.find('_sysborder').width(this.config.width);
		this.find('_sysborder').height(this.config.height);
		console.log(this.config);
		this.layer.draw();
	},
	find: function(name) {
		for(var i in this.layer.children) {
			var c = this.layer.children[i];
			if (c.attrs.name == name)
				return c;
		}
		return null;
	},
	propertychange: function(e){
		var $editor = $(e.currentTarget).closest("tbody");
		var data = {
		};
		$editor.find('.property-input').each(function(){
			var $el = $(this);
			data[$el.attr('key')] = $el.val();
		});
		var item = this.createItem(data, true);
		var i = this.list.indexOf(this.selected.item);
		console.log(i);
		if (i > -1)
			this.list[i] = item;
		this.selected = null;
		
		this.render();
		this.buildPropEditor(item);
		this.selectView(this.findView(item));
	},
	newitemclick: function(){
		var me = this;
		this.createItem({
			x: random(100),
			y: random(100),
			width: 200,
			height: 100,
			text: "label"+(me.layer.children.length+1),
		});
		this.render();
		console.log('new item added');
	},
	attrsFromView: function(view){
		//console.log(c.className);
		switch(view.className){
		case 'Label':
			var frame = view.ui.frame;
			var text = view.ui.text;
			return {
				x: view.x(),
				y: view.y(),
				width: frame.width(),
				height: frame.height(),
				text: text.text(),
				align: text.align(),
				verticalAlign: text.verticalAlign(),
			};
			break;
		}
	},
	buildResult: function(){
		var me = this;
		//var all = this.layer.children.toArray();
		var result = {
			title: me.config.title,
			width: me.config.width,
			height: me.config.height,
			rotate: me.config.rotate,
			items: [],
		}
		for(var i in this.list) {
			var c = this.list[i];
			result.items.push(c.attrs);
		}
		
		result.items.sort(function(a,b){
			return a.zIndex - b.zIndex;
		});
		console.log(result);
		//console.log(result.items[0]);
		return result;
	},
	saveclick: function(){
		localStorage.lastSaved = JSON.stringify(this.buildResult());
		
		var json = JSON.stringify(this.buildResult());
		$.post("api/save", {
			title: this.config.title,
			data: json
		}, function(s){
			console.log(s);
			location.reload();
			alert("저장되었습니다.");
		});
	},
	render: function() {
		var me = this;
		if(this.layer)
			this.layer.destroy();
		this.layer = new Konva.Layer({});
		this.stage.add(this.layer);
		
		// valid area
		this.layer.add(new Konva.Rect({
			name: '_sysborder',
			x: 0, 
			y: 0, 
			width: me.config.width,
			height: me.config.height,
			stroke: '#23c4ff',
			strokeWidth: 1,
		}));			

		for(var i in this.list) {
			var c = this.list[i];
			this.createView(c);
		}
		this.stage.draw();
	},
	createView: function(item){
		var me = this;
		var a = item.attrs;
		var type = a.type.toLowerCase();
		var view = new Konva.Label({
			x: a.x*1,
			y: a.y*1,
			draggable: true,
		});
		view.ui = {};
		var frame = new Konva.Rect({
			x: 0,
			y: 0,
			width: a.width,
			height: a.height,
			fill: a.backgroundColor,
			stroke: "",
		});
		view.add(frame);
		view.ui.frame = frame;
		
		var t = new Konva.Text({
			x: 0,
			y: 0,
			text: a.text,
			fontSize: a.fontSize,
			width: a.width,
			height: a.height,
			align: a.align,
			fill: a.color,
			verticalAlign: a.verticalAlign,
		});
		view.add(t);
		view.ui.text = t;
		
		view.item = item;

		if (type == 'image'){
			var imageObj = new Image();
			imageObj.onload = function(){
				var img = new Konva.Image({
					x: 0,
					y: 0,
					image: imageObj,
					width: a.width,
					height: a.height,
				});
				view.add(img);
				img.moveToBottom();
				me.layer.draw();
			}
			imageObj.src = a.imageUrl;
		}		
		
		view.on("mousedown", function(e){
			if (me.editing)
				return;
			var t = e.currentTarget;
			me.selectView(t);
			me.buildPropEditor(me.selected.item);
		});
		view.on("mouseup", function(e){
			if (me.editing) {
				me.editing = false;
				return;
			}
			console.log(e);
			var data = me.attrsFromView(e.currentTarget);
			e.currentTarget.item.setAttrs(data);			
			me.buildPropEditor(me.selected.item);
		});
		this.layer.add(view);
		return view;
	},	
	createItem: function(c, dontpush){
		var newItem;
		var me = this;
		var cls = ItemLabel;
		switch(c.type) {
		case 'Image': cls = ItemImage; break;
		}
		newItem = new cls(c);

		if(!dontpush)
			this.list.push(newItem);
		
		return newItem;
	},
	selectView: function(view){
		var me = this;
		console.log(view.item.attrs);
		console.log(me.selected);
		//console.log(t.width());
		if(me.selected)
			me.selected.ui.frame.stroke("");
		me.selected = view;
		if(view) {
			view.ui.frame.stroke("red");
			this.layer.draw();
		}
	},
	buildPropEditor: function(item){
		var $el = this.$('#property-editor tbody');
		$el.empty();
		var data = item.attrs;
		for(var i in data) {
			var params = {};
			var html;
			switch(i.toLowerCase()) {
			case 'type':
				html = this.propTypeTemplate({
					key: i,
					value: data[i],
				});	
				console.log(data[i]);				
				break;
			default:
				html = this.propEditorTemplate({
					key: i,
					value: data[i],
				});
			}
			$el.append(html);			
		}
	},
	clear: function(){
		this.list = [];
		if(this.layer)
			this.layer.destroy();
		this.layer = new Konva.Layer({});
		this.stage.add(this.layer);
	},
	load: function(json){
		var me = this;
		this.clear();
		if (typeof(json) == 'string')
			json = JSON.parse(json);
		this.data = json;
		if(json.width)
			this.config.width = json.width;
		if(json.height)
			this.config.height = json.height;
		if(json.title)
			this.config.title = json.title;
		if(typeof json.rotate != "undefined"){
			this.config.rotate = json.rotate;	
		}else{
			this.config.rotate = 0;
		}	
		this.$('#sTitle').val(this.config.title);
		this.$('#iWidth').val(this.config.width);
		this.$('#iHeight').val(this.config.height);
		this.$('#iRotate').val(this.config.rotate);
		//alert(me.config.width);
		for(var i in json.items) {
			this.createItem(json.items[i]);
		}
		this.render();
	},
	saveBackup: function(){
		localStorage.lastSaved =  JSON.stringify(this.buildResult());
	},
	initialize: function(){
		var me = this;		
		this.propEditorTemplate = _.template($('#prop-editor-template').html());
		this.propTypeTemplate = _.template($('#prop-type-template').html());
		this.stage = new Konva.Stage({
			container: '#canvas',
			width: 1920,
			height: 1080,
		});
		
		this.$('#json-editor').modal({
			backdrop: 'static',
			show: false,
		}).on('hide.bs.modal', function (e) {			
			var $el = me.$('#json-editor').find('textarea');
			if($el.attr('dirty') == 'true' && !confirm("저장하지 않은 내용이 손실됩니다."))
				return false;
		});
		
		this.$('#data-editor').modal({
			backdrop: 'static',
			show: false,
		}).on('hide.bs.modal', function (e) {			
			try {
				sampleData = JSON.parse(me.$('#data-editor textarea').val());
				localStorage.sampleData = me.$('#data-editor textarea').val();
			} catch(e){
				alert("데이터에러\n"+e);
			}
		});
		
		this.clear();
	},
	checkDirty: function(){
		if (this.isDirty()) {
			if(!confirm("변경사항이 저장되지 않았습니다."))
				throw "abort(NOT SAVED)";
		}			
	},
	isDirty: function(){	
		//console.log(this.backup, this.buildResult());
		return localStorage.lastSaved != JSON.stringify(this.buildResult());
	}
});
