(function umd(root,factory){
	if (typeof module === "object" && typeof exports === "object")
		module.exports=factory();
	else if (typeof define === "function" && define.amd)
		define([],factory);
	else
		root.OPCTechs_Soft = factory();
})(this, function factory(){
	"use strict";
	// 點位分段
	OPCTechs_Soft.prototype.Slice = function (_pot, _len) {
		// 檢查分段設置
		_len = parseInt(_len) || 999;
		_len = Math.min(_len , 999);
		if (!_len) {
			return [];
		}
		var arrTmpObj = [];
		var kLen = Object.keys(_pot).length;
		var stop = Math.ceil(kLen / _len);
		var tmpArr = Object.keys(_pot);
		for (var _idx = 0; _idx < stop; _idx++) {
			var tmpObj = {};
			tmpArr.slice((_len * _idx), (_len * (_idx + 1))).forEach(function(_k){
				tmpObj[_k] = _pot[_k];
			});
			arrTmpObj.push(tmpObj);
		}
		return arrTmpObj;
	}
	// 物件字串化
	OPCTechs_Soft.prototype.Stringify = function (_pot) {
		var _$pot = JSON.parse(JSON.stringify(_pot));
		var _$tmp = [];
		var _$act = "";
		var _$cmd = "";
		Object.keys(_$pot).forEach(function(_pn, aaa){
			if (_pn == "action") {
				_$act = _$pot[_pn] == "W" ? "W" : "R";
			} else {
				var chk = ["D", "R", "S"].includes(_pn.substr(0, 1));
				var len = _pn.length - 1;
				var num = parseInt(_pn.substr(1, len));
				if (chk && !isNaN(num)) {
					var tmp = _pn.substr(0, 1) + num.toString().padLeftZero(5);
					var dec = parseInt(_$pot[_pn].decimal) || 0;
					tmp += dec.toString().padLeftZero(2) + "  " + (_$act == "W" ? _$pot[_pn].value : "");
					_$tmp.push(tmp);
				}
			}
		});
		if (_$tmp.length) {
			_$cmd = _$act + Math.min(_$tmp.length, 999).toString().padLeftZero(3) + _$tmp.join(";") + ";";
		}
		return _$cmd;
	}
	// 字串物件化
	OPCTechs_Soft.prototype.Parse = function (_cmd) {
		var rtnObj = {};
		if (["R", "W"].includes(_cmd.substr(0, 1))) {
			var amt = parseInt(_cmd.substr(1, 3));
			var tags = _cmd.substr(4).split(";");
			for (var _$i=0; _$i < amt; _$i++) {
				if (typeof tags[_$i] != "string") break;
				// OPC tag name
				var _$name  = tags[_$i].substr(0, 6);
				var _$decimal = parseInt(tags[_$i].substr(6, 2)) || 0;
				// OPC tag value
				var _$value = tags[_$i].substr(10).trim();
				// on => 1 , off => 0
				if (_$name.substr(0, 1) == "R") {
					_$value = this._objOnOff[_$value];
				}
				rtnObj[_$name] = { "decimal" : _$decimal, "value" : _$value };
			}
			rtnObj["action"] = _cmd.substr(0, 1) == "R"
		}
		return rtnObj;
	}
	// 連線參數(讀取/設置)
	OPCTechs_Soft.prototype.Options = function (_config) {
		if (typeof _config == "object" && Object.keys(_config).length > 0) {
			var self = this;
			Object.keys(self._settings).forEach(function(_k){
				// 有傳入且形態相同
				if (_config[_k] && typeof self._settings[_k] == typeof _config[_k]) {
					self._settings[_k] = _config[_k];
				} else if (_config[_k]) {
					console.log("Confing[" + _k + "] Type Error");
				}
			});
		}
		return this._settings;
	}
	// 連線狀態
	OPCTechs_Soft.prototype.IsConnection = function () {
		return this._termination;
	}
	// 收值狀態
	OPCTechs_Soft.prototype.IsArrived = function () {
		return this._arrived;
	}
	// 啟動
	OPCTechs_Soft.prototype.Startup = function (_cmd) {
		var self = this;
		var tls = self._settings.useSSL ? "https:" : "http:";
		self._objSocket = io.connect(tls + "//" + self._settings.host + ":" + self._settings.port, {
			autoConnect: self._settings.autoConnect,
			reconnect: self._settings.reconnect,
			transports: ["websocket", "polling"]
		});
		// 接收回調
		self._objSocket.on("data", function(_strMessage) {
			var data = self.Parse(_strMessage);
			if (Object.keys(data).length) {
				delete data.action;
				if (typeof self._fnArrived == "function") {
					self._fnArrived && self._fnArrived(data);
				}
				if (!self._arrived) {
					self._arrived = true;
				}
			}
		});
		// 錯誤回調
		self._objSocket.on("connect_error", function(err) {
			if (typeof self._fnFail == "function") {
				self._fnFail && self._fnFail(err, "error");
			}
		});
		// 錯誤回調
		self._objSocket.on("connect_failed", function(err) {
			if (typeof self._fnFail == "function") {
				self._fnFail && self._fnFail(err, "failed");
			}
		});
		// 連線回調
		self._objSocket.on("connect", function() {
			self._termination = true;
			self._objSocket.emit("getData", _cmd);
			if (typeof self._fnSucc == "function") {
				self._fnSucc && self._fnSucc(self._objSocket.id);
			}
		});
	}
	// 停止
	OPCTechs_Soft.prototype.Shutdown = function () {
		if (this._termination) {
			this._objSocket.disconnect();
		}
	}
	// 下指令
	OPCTechs_Soft.prototype.Command = function (_cmd, _fnCallback) {
		var once_socket = io.connect(this._settings.host + ":" + this._settings.port);
		// 接收回調
		once_socket.on("data", function(_strMessage) {
			once_socket.disconnect();
			if (typeof _fncallback == "function") {
				_fncallback && _fncallback();
			}
		});
		// 連線回調
		once_socket.on("connect", function() {
			once_socket.emit("getData", _cmd);
		});
	}
	// 設置收值回調
	OPCTechs_Soft.prototype.SetFnArrived = function (_callback) {
		this._fnArrived = _callback;
	}
	// 設置連線成功回調
	OPCTechs_Soft.prototype.SetFnSucc = function (_callback) {
		this._fnSucc = _callback;
	}
	// 設置連線失敗回調
	OPCTechs_Soft.prototype.SetFnFail = function (_callback) {
		this._fnFail = _callback;
	}
	
	function OPCTechs_Soft () {
		// 連線參數
		this._settings = {
			host : document.domain,
			port : "8888",
			useSSL: false,
			autoConnect : true,
			reconnect : true
		};
		// 收值狀態
		this._arrived = false;
		// 連線狀態
		this._termination = false;
		// socket.io物件
		this._objSocket = null;
		// R點數值對應
		this._objOnOff = { on: 1, off: 0 };
		// 相關回調函數
		this._fnArrived = null;
		this._fnSucc = null;
		this._fnFail = null;
	}
	
	return OPCTechs_Soft;
});
