"use strict";

var ImageDisplay = require("../ImageDisplay.js"),
	Color = require("color"),
	Condicio = require("condicio"),
	ParamValidation = require("../ParamValidation.js"),
	Matrix = require("gl-matrix"),
	Utility = require("../Utility.js"),
	Effect = require("./Effect.js"),
	jQuery = require("jquery"),
	CvtForJson = require("../CvtForJson.js"),
	Style = require("./Style.js"),
	_ = require("lodash");
	
/**
 * @class ViewPID.ViewPID
 * PID渲染场景
 * 
 * 提供加载图纸,显示及对图纸操作的功能
 *
 * 不应该直接创建,应该通过{@link Factory}提供的createViewPID得到
 */
function ViewPID(session, elem, objectID, enableSSL, proxyUri) {
	var _this = this;

    this.session = session;
    this.objectID = objectID;
	this.pickHandlerID = null;
	this.hoverHandlerID = null;
	this.isLoadFile = false;
	
    this.display = new ImageDisplay(session, objectID, elem, enableSSL, proxyUri);
};

ViewPID.prototype = _.create(ViewPID.prototype, {
	constructor: ViewPID
});

ViewPID.prototype.release = function(){
	if(this.pickHandlerID)
	{
		this.session.unregisterCallback(this.pickHandlerID);
	}
	
	if(this.hoverHandlerID)
	{
		this.session.unregisterCallback(this.hoverHandlerID);
	}
	
	this.isLoadFile = false;
	this.display.release();
};

/**
 * 加载dwg图纸
 *
 * @param {String} 		url 			所加载图纸的地址,支持"http://...../x.dwg"和"file:///.../x.dwg"格式
 * @param {Function} 	callback		加载图纸回调
 * @param {Error}		callback.err	加载失败,指示错误信息(system_error、NetworkError、DataError),加载成功返回空
 */
ViewPID.prototype.loadFile = function(url, callback) {
	Condicio.checkIsString(url, "The type of url must be 'string'");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	
	var _this = this;
	var callbackWrapper = function (error, result) {
        if (error) {
            callback(error, null);
        }
        else{
			_this.isLoadFile = true;
			callback(null, null);	
		}
    };
	
	var callbackID = Utility.genGUID();
	var params = {
		url: url,
		callbackID: callbackID
	};
	
	this.session.registerCallback(callbackID, callbackWrapper,"loadFile");
	
	this.session.request(this.objectID, "loadFile", params);
};

/**
 * 适应窗口大小
 * @param {Number} 	[zoomMultiplier = 0.98]		缩放倍数((0,1)表示缩小的倍数,(1,+∞)表示放大倍数,1表示整张图纸刚好充满显示区)
 */
ViewPID.prototype.zoomExtents = function(zoomMultiplier) {
	var multiplier = 0.98;
	if (!Condicio.isUndefined(zoomMultiplier))
        multiplier = zoomMultiplier;
	Condicio.checkArgument(multiplier > 0, "param zoomMultiplier must greater than 0!");
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	this.session.request(this.objectID, "zoomExtents", {zoomMultiplier: multiplier});
};

/**
 * 设置选中回调
 * 需要注意的点是:单击pickHandler只会回复一次交互结果;双击的情况下会先回两次单击交互结果再回一次双击交互结果 
 *
 * @param {Function} 	pickHandler    						当有选择操作(例如点选)发生时,回调
 * @param {Error}    	pickHandler.err						选择过程中发生错误
 * @param {Object}  	pickHandler.msg						选中的结果
 * @param {String[]} 	pickHandler.msg.handles    			选中的实体集合
 * @param {string}		pickHandler.msg.pickMethod			标识鼠标操作的类型(pointPick/boxPick/RButtonPick/LButtonDBLCLK)
 * @param {double}  	pickHandler.msg.x					选中点的x坐标(世界坐标系下的x坐标)
 * @param {double}  	pickHandler.msg.y					选中点的y坐标(世界坐标系下的y坐标)
 * @param {Number}		[hoverTime = 300]					框选时鼠标悬停多久(毫秒)返回选中的结果
 */
ViewPID.prototype.setPickHandler = function(pickHandler, hoverTime) {
	Condicio.checkIsFunction(pickHandler, "The type of pickHandler must be 'function'");
	
	var time = 300;
	if (!Condicio.isUndefined(hoverTime))
        time = hoverTime;
	Condicio.checkArgument(time > 0, "param hoverTime must greater than 0!");
	
	if (this.pickHandlerID)
		this.session.unregisterCallback(this.pickHandlerID);
	
	this.pickHandlerID = Utility.genGUID();
	var params = {
		pickHandlerID: this.pickHandlerID,
		hoverTime: time
	};
	
	this.session.registerCallback(this.pickHandlerID, pickHandler, "setPickHandler", true);
	
    this.session.request(this.objectID, "setPickHandler", params);
};

/**
 * 模型定位
 *
 * scale的值不给时只将实体居中,scale给值时将实体放大居中
 *
 * @param {String[]/String} 	handles				需要定位的实体标识集合/需要定位的实体标识
 * @param {double}				[scale]				当scale=1时,元件在保证完整的情况下最大化显示在屏幕上;
 *													scale:元件在屏幕上显示的长宽分别占元件最大化显示时长宽的百分比(取值范围:(0.0~1.0])
 */
ViewPID.prototype.centerEntity = function(handles, scale) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	if(Condicio.isString(handles))
	{
		handles = [handles];
	}
	ParamValidation.checkIsTypeArray(handles, String, "The type of handles must be 'String Array' and valid");
	Condicio.checkArgument(handles.length !== 0, "The handles-Array must`t be NULL!");
	
	var params = {
		handles: handles
	};
	
	if(!Condicio.isUndefined(scale))
	{
		Condicio.checkArgument(scale > 0.0 && scale <= 1.0, "The scale must: > 0.0 && <= 1.0 !");
		params.scale = scale;
	}	
	
	this.session.request(this.objectID, "centerEntity", params);
};

/**
 * 高亮
 *
 * @param {String[]} 		handles		需要高亮的实体标识集合
 * @param {boolean} 		light		是否高亮
 */
ViewPID.prototype.highlight = function(handles, light) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	ParamValidation.checkIsTypeArray(handles, String, "The type of handles must be 'String Array' and valid");
	Condicio.checkIsBoolean(light, "The light must be 'boolean'!");
		
	var param = {
		handles: handles,
		light: light
	};
	this.session.request(this.objectID, "highlight", param);
};

/**
 * @deprecated
 * 加载标签
 *
 * @param {String} 		url 					标签的下载地址,支持"http://...../x.dwg"和"file:///.../x.dwg"格式
 * @param {Function} 	callback				加载标签回调
 * @param {Error}		callback.err			加载失败,指示错误信息
 *						err {NetworkError}      标签下载失败
 *                		err {DataError}         标签数据出错
 * @param {string}		callback.handle			加载成功,返回标签
 */
ViewPID.prototype.loadLabelTemplate = function(url, callback) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsString(url, "The type of url must be 'string'");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "loadLabelTemplate");
	
	var param = {
		url: url,
		callbackID: callbackID
	};
	
	this.session.request(this.objectID, "loadLabelTemplate", param);
};

/**
 * @deprecated
 * 添加标签
 *
 * @param {Object}      option	
 * @param {vec2} 		option.position    					添加标签的位置
 * @param {object} 		option.textOption					标签的文字(key:文字的属性,value:标签的文字,需自带换行(插入'\n'))
 * @param {String}		option.handle						添加标签
 * @param {Function} 	callback							添加标签的回调
 * @param {Error}		callback.err						添加失败,指示错误信息
 * 						err {DataError}      				数据出错
 * @param {string}		callback.label						成功返回标签
 */
ViewPID.prototype.addLabel = function(option, callback) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsObject(option, "The type of option must be 'Object'!");
	Condicio.checkIsString(option.handle, "The type of handle must be 'string'");
	Condicio.checkIsObject(option.textOption, "The type of textOption must be 'Object'!");
	ParamValidation.checkIsVec2(option.position, "option.position must be a 'vec2'");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	
	for(var i in option.textOption){
		Condicio.checkIsString(i, "The type of key must be 'string'");
		Condicio.checkIsString(option.textOption[i], "The type of value must be 'string'");
		}
	
	var numberArray = [];
	for (var j = 0; j < 2; ++j) {
		numberArray.push(option.position[j]);
	}
	option.position = numberArray;
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "addLabel");
	
	var param = {
		option: option,
		callbackID: callbackID
	};
	
	this.session.request(this.objectID, "addLabel", param);
};

/**
 * @deprecated
 * 删除标签
 *
 * @param {string}		label			删除标签
 */
ViewPID.prototype.removeLabel = function(label) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsString(label, "The type of label must be 'string'");
	var entities = [];
	entities.push(label);
	this.session.request(this.objectID, "removeEntities", {entities: entities});
};

/**
 * 删除实体
 *
 * @param {string[]}		entities			删除实体的集合
 */
ViewPID.prototype.removeEntities = function(entities) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	ParamValidation.checkIsTypeArray(entities, String, "The type of entities must be 'String Array' and valid");
	
	this.session.request(this.objectID, "removeEntities", {entities: entities});
};

/**
 * 显隐实体
 *
 * @param {String[]} 	handles		 					需要显隐的实体标识集合 
 * @param {boolean} 	visible							显隐状态(true显示,false隐藏)
 */
ViewPID.prototype.changeVisibility = function(handles, visible){
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	ParamValidation.checkIsTypeArray(handles, String, "The type of handles must be 'String Array' and valid");
	Condicio.checkArgument(handles.length != 0, "The handles-Array must`t be NULL!");
	Condicio.checkIsBoolean(visible, "The visible must be 'boolean'!");
	
	var param = {
		handles: handles,
		visible: visible
	};
	
	this.session.request(this.objectID, "changeVisibility", param);
};

 /**
 * 创建变色效果
 *
 * @param {String[]} 	handles			需要改变颜色的实体标识集合				
 * @param {Color}		color			目标颜色
 *
 * @return {ViewPID.Effect}
 */
ViewPID.prototype.createColorChangeEffect = function (handles, color) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	ParamValidation.checkIsTypeArray(handles, String,  "The  type of handles must be 'String Array' and valid!");
	Condicio.checkArgument(handles.length !== 0, "The number of handles must`t be NULL!");
	//Condicio.checkIsType(color, Color, "The color must be 'Color type'!");
	
	var effectID = Utility.genGUID();
	var params = {
		effectID: effectID,
		handles: handles,
		color: color.rgbaArray()
	};
	
    this.session.request(this.objectID, "createColorChangeEffect", params);

    return new Effect(effectID);
};

/**
 * 释放效果资源
 *
 * @param {ViewPID.Effect[]} effects 待释放的效果资源集合
 */
ViewPID.prototype.releaseEffect = function (effects) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
    ParamValidation.checkIsTypeArray(effects, Effect, "The type of effects must be 'Effect Array' and valid");

    var objectIDs = [];
    for (var i = 0; i < effects.length; ++i) {
		objectIDs.push(effects[i].objectID);
    }
	
    this.session.request(this.objectID, "releaseEffect", { objectIDs: objectIDs });
};

/**
 * 增加效果
 *
 * @param {ViewPID.Effect} effect 	效果
 */
ViewPID.prototype.addEffect = function (effect) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
    Condicio.checkNotNull(effect, "Effect must`t be NULL!");
    Condicio.checkNotUndefined(effect, "Effect is undefined!");
	Condicio.checkIsType(effect, Effect, "The type of effect must be PidEffect");

    this.session.request(this.objectID, "addEffect", { effectID: effect.objectID });
	
	effect.on(this.session);
};

/**
 * 删除效果
 *
 * @param {ViewPID.Effect} effect 	效果
 */
ViewPID.prototype.removeEffect = function (effect) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
    Condicio.checkNotNull(effect, "Effect must`t be NULL!");
    Condicio.checkNotUndefined(effect, "Effect is undefined!");
	Condicio.checkIsType(effect, Effect, "The type of effect must be PidEffect");

    this.session.request(this.objectID, "removeEffect", { effectID: effect.objectID });
	
	effect.off(this.session);
};

/**
 * 屏幕截图
 *
 * @param {Function}   callback     		获取屏幕截图完成后的回调
 * @param {Error}      callback.err 		获取屏幕截图失败返回错误
 * @param {String}     callback.screenShot  获取屏幕截图成功返回截图数据
 */
 ViewPID.prototype.captureScreenShot = function(callback){
	 Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	 Condicio.checkIsFunction(callback, Function, "The type of 'callback' must be 'Function'!");
	 
	 var callbackWrapper = function(error, result){
		 if(error){
			 callback(error, null);
		 }
		 else
			 callback(null, result.imageData);
	 };
	 
	 var callbackID = Utility.genGUID();
	 this.session.registerCallback(callbackID, callbackWrapper, "captureScreenShot");
	 
	 this.session.request(this.objectID, "captureScreenShot", {callbackID: callbackID});
 };

 /**
 * 设置图纸背景色
 * 需要注意的点是:本次图纸浏览的背景色需要在加载图纸之前设置
 *			
 * @param {Color}		color			目标颜色
 */
ViewPID.prototype.setBackgroundColor = function (color) {
	//Condicio.checkIsType(color, Color, "The color must be 'Color type'!");
	
	var params = {
		color: color.rgbaArray()
	};
	
    this.session.request(this.objectID, "setBackgroundColor", params);
};

/**
 * 添加弧线
 * @param {object} 		option
 * @param {object}  	[option.style]  	    					添加弧线属性,参照ViewPID.Style.ArcStyle的定义
 * @param {vec2[]} 		option.pointPairs 						    弧线点集合,每两个点确定一条弧线,点的个数为偶数个。(pointPairs需是世界坐标下的点)
 * @param {Function} 	callback							      	
 * @param {Error} 	    callback.error								添加弧线返回错误
 * @param {string[]}    callback.arcs								返回弧线
 */
ViewPID.prototype.addArcs = function(option,callback)
{	
	var defaultStyle = {
		style: Style.ArcStyle
	};
	var newOption = jQuery.extend(true,{}, defaultStyle, option);
	
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	ParamValidation.checkIsArcsStyle(newOption.style);
	Condicio.checkIsObject(newOption, "The type of option must be 'Object'!");
	Condicio.checkIsFunction(callback,"The type of callback must be 'Function'!");
	Condicio.checkArgument(newOption.pointPairs.length !== 0, "The pointPairs can`t add arc! ");
	ParamValidation.checkIsVec2Array(newOption.pointPairs, "the type of pointPairs must be a 'vec2 Array'")
	newOption.pointPairs = CvtForJson.cvtVec2Array(newOption.pointPairs);
	newOption.style.color = newOption.style.color.rgbaArray();
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "addArcs");
    var params = {
		option: newOption,
		callbackID: callbackID
    };
    this.session.request(this.objectID, "addArcs", params);
};

/**
 * 添加文本框
 *
 * @param {Object}      option	
 * @param {vec2} 		option.position   				添加文本框的位置(表示文字的左上角)(position需是世界坐标下的点)
 * @param {String} 		option.text			   			文本框内文字,需自带换行(插入'\n')
 * @param {Object} 	    [option.textFrameStyle] 		绘制属性,参照ViewPID.Style.TextFrameStyle的定义
 * @param {Function} 	callback						添加文本框的回调
 * @param {Error} 	    callback.Error					错误信息
 * @param {string}		callback.textFrame				返回文本框
 */
ViewPID.prototype.addTextFrame = function(option, callback) {
	var defaultOption = {
		textFrameStyle: Style.TextFrameStyle
	};
	var newOption = jQuery.extend(true, {}, defaultOption, option);
	
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsObject(newOption, "The type of option must be 'Object'!");
	Condicio.checkIsString(newOption.text, "param text must be a string");
	ParamValidation.checkIsVec2(newOption.position, "option.position must be a 'vec2'");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	ParamValidation.checkIsPidTextFrameStyle(newOption.textFrameStyle);
	
	newOption.textFrameStyle.text.color = newOption.textFrameStyle.text.color.rgbaArray();
	newOption.textFrameStyle.backgroundFillColor = newOption.textFrameStyle.backgroundFillColor.rgbaArray();
	newOption.position = CvtForJson.cvtVec2(newOption.position);
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "addTextFrame");
	
	var param = {
		option: newOption,
		callbackID: callbackID
	};
	
	this.session.request(this.objectID, "addTextFrame", param);
};

/**
 * 添加线
 *
 * @param {Object}      option	
 * @param {vec2[]}		option.pointPairs					连线点集合,每两点(世界坐标下的点)确定一条线,点的个数为偶数
 * 															pointPairs[0]与pointPairs[1]确定一条线,pointPairs[2]与pointPairs[3]确定一条线
 *															pointPairs需是世界坐标下的点
 * @param {Object} 	    [option.lineStyle] 		    		绘制属性,参照ViewPID.Style.LineStyle的定义
 * @param {Function} 	callback							添加标签的回调
 * @param {Error} 	    callback.Error						错误信息
 * @param {string[]}	callback.lines						返回线集合
 */
ViewPID.prototype.addLines = function(option, callback) {
	var defaultOption = {
		lineStyle: Style.LineStyle
	};
	var newOption = jQuery.extend(true, {}, defaultOption, option);
	
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsObject(newOption, "The type of option must be 'Object'!");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	ParamValidation.checkIsVec2Array(newOption.pointPairs, "the type of pointPairs must be a 'vec2 Array'")
	Condicio.checkArgument(newOption.pointPairs.length !== 0, "The number of pointPairs must`t be NULL!");
	Condicio.checkArgument(newOption.lineStyle.width >= 0 && newOption.lineStyle.width <= 2.11, "The number of lineStyle.width must >= 0 && <=2.11!");
	ParamValidation.checkIsLineStyle(newOption.lineStyle);
		
	newOption.lineStyle.color = newOption.lineStyle.color.rgbaArray();
	newOption.pointPairs = CvtForJson.cvtVec2Array(newOption.pointPairs);
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "addLines");
	
	var param = {
		option: newOption,
		callbackID: callbackID
	};
	
	this.session.request(this.objectID, "addLines", param);
};

/**
 * 二维显示窗口的窗口坐标转世界坐标
 *
 * @param {vec2[]}      screenPoints					窗口屏幕坐标
 * @param {Function}  	callback						回调
 * @param {Error} 	    callback.Error					错误信息
 * @param {vec2[]}		callback.worldPoints			返回窗口屏幕坐标对应的世界坐标
 */
ViewPID.prototype.screenToWorld = function(screenPoints, callback) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	ParamValidation.checkIsVec2Array(screenPoints, "the type of screenPoints must be a 'vec2 Array'")
	Condicio.checkArgument(screenPoints.length !== 0, "The number of screenPoints must`t be NULL!");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	
	screenPoints = CvtForJson.cvtVec2Array(screenPoints);
	
	var callbackWrapper = function (error, result) {
        if (error) {
            callback(error, null);
        }
        else{
			var worldPoints = [];
			for(var i=0; i<result.worldPoints.length; ++i){
				worldPoints.push(Matrix.vec2.fromValues(result.worldPoints[i].x, result.worldPoints[i].y));
			}
			callback(null, worldPoints);
		}
    };
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callbackWrapper, "screenToWorld");
	
	var param = {
		screenPoints: screenPoints,
		callbackID: callbackID
	};
	
	this.session.request(this.objectID, "screenToWorld", param);
};

/**
 * @deprecated
 * 得到图纸上的所有entity
 *
 * @param {Function} 	callback							回调函数
 * @param {Error} 	    callback.Error						错误信息
 * @param {string[]}	callback.entities					返回实体集合
 */
ViewPID.prototype.getAllEntities = function(callback) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "getAllEntities");
	
	this.session.request(this.objectID, "getAllEntities", {callbackID: callbackID});
};

/**
 * 更新弧线
 *
 * @param {object} 			option
 * @param {string[]}		option.arcs					想要更新的arcs
 * @param {vec2[]} 			[option.pointPairs]			更新的弧线的点的个数为arcs个数的2倍,每两个对应arcs数组中一个的弧
 * @param {object}  		[option.style]				style的更新,同时传三个参数,不给值的参还原默认值。参照ViewPID.Style.ArcStyle的定义
 */
ViewPID.prototype.updateArcs = function(option) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first");
	Condicio.checkIsObject(option, "param option must be a Object");
	ParamValidation.checkIsTypeArray(option.arcs, String, "The type of arcs must be 'String Array' and valid");
	Condicio.checkArgument(option.arcs.length !== 0, "The arcs is empty");

	if(!Condicio.isUndefined(option.pointPairs)){
		Condicio.checkArgument(option.pointPairs.length === option.arcs.length * 2, "The pointPairs Number can't updateArcs");
		ParamValidation.checkIsVec2Array(option.pointPairs, "the type of pointPairs must be 'vec2 Array'")
		option.pointPairs = CvtForJson.cvtVec2Array(option.pointPairs);	
	}
	
	if(!Condicio.isUndefined(option.style)){
		option.style = jQuery.extend(true,{}, Style.ArcStyle, option.style);
		ParamValidation.checkIsArcsStyle(option.style);
		option.style.color = option.style.color.rgbaArray();
	}
	
	this.session.request(this.objectID, "updateArcs", {option : option});
};

/**
 * 添加多边形
 * @param {vec2[]}		pointsArray							创建多边形的点集合,所有点(世界坐标下的点),点数不少于3个
 * @param {Object}      options	
 * @param {Object} 	    [options.polygonStyle] 		    	绘制属性,参照ViewPID.Style.PolygonStyle的定义
 * @param {Function} 	callback							添加多边形的回调
 * @param {Error} 	    callback.Error						错误信息
 * @param {string}		callback.polygon					返回多边形
 */
ViewPID.prototype.addPolygon = function(pointsArray, options, callback) {
	var defaultOptions = {
		polygonStyle: Style.PolygonStyle
	};
	var extendOptions = jQuery.extend(true, {}, defaultOptions, options);
	
	ParamValidation.checkIsVec2Array(pointsArray, "the type of pointsArray must be a 'vec2 Array'")
	Condicio.checkArgument(pointsArray.length >= 3, "The points can`t draw polygon! ");
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsObject(extendOptions, "The type of options must be 'Object'!");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");	
	Condicio.checkIsObject(extendOptions.polygonStyle, "The type of polygonStyle must be 'Object'!");
	//Condicio.checkIsType(extendOptions.polygonStyle.color, Color, "The type of PolygonStyle.color must be 'COLOR'!");
		
	extendOptions.polygonStyle.color = extendOptions.polygonStyle.color.rgbaArray();
	pointsArray = CvtForJson.cvtVec2Array(pointsArray);
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callback, "addPolygon");
	
	var param = {
		pointsArray: pointsArray,
		options: extendOptions,
		callbackID: callbackID
	};
	
	this.session.request(this.objectID, "addPolygon", param);
};

/**
 * 鼠标左键绑定对应操作
 * 若左键不想绑定任何操作,则可以给空字符串;例如:leftButtonOperation = ""
 *
 * @param {String}		leftButtonOperation				鼠标左键要绑定的操作(鼠标左键拖动可绑定平移(Pan)或框选(BoxSelection))
 */
ViewPID.prototype.bindLeftButtonOperation = function(leftButtonOperation) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first ");
	Condicio.checkIsString(leftButtonOperation, "The type of leftButtonOperation must be 'string'");
	Condicio.checkArgument(leftButtonOperation === "" || leftButtonOperation === "Pan" || leftButtonOperation === "BoxSelection", "leftButtonOperation must valid!");
	
	var params = {
		leftButtonOperation: leftButtonOperation
	};
	
    this.session.request(this.objectID, "bindLeftButtonOperation", params);
};

/**
 * 得到图纸上的所有的文字实体
 *
 * @param {Function} 	callback    						回调函数
 * @param {Error}    	callback.err						错误信息
 * @param {Object[]}  	callback.infos						返回的所有结果信息
 * @param {String} 		callback.infos.handle    			文字实体的handle
 * @param {string}		callback.infos.text					文字实体中存放的文字
 * @param {vec2}  		callback.infos.minPoint				文字实体包围盒的最小值(世界坐标系)
 * @param {vec2}  		callback.infos.maxPoint				文字实体包围盒的最大值(世界坐标系)
 */
ViewPID.prototype.getAllTextInfos = function(callback) {
	Condicio.checkArgument(this.isLoadFile === true, "The drawing must be loaded first");
	Condicio.checkIsFunction(callback, "The type of callback must be 'function'");
	
	var callbackWrapper = function (error, result) {
		if (!error){
			var infos = result.infos;

			for(var i = 0; i<infos.length; ++i)
			{
				infos[i].minPoint = CvtForJson.cvtToVec2(infos[i].minPoint);
				infos[i].maxPoint = CvtForJson.cvtToVec2(infos[i].maxPoint);
			}

			callback(null, infos);
		}
		else {
			callback(error, null);
		}
	};
	
	var callbackID = Utility.genGUID();
	this.session.registerCallback(callbackID, callbackWrapper, "getAllTextInfos");
	
	this.session.request(this.objectID, "getAllTextInfos", {callbackID: callbackID});
};

/**
 * 设置鼠标悬停操作交互
 *
 * @param {Function} 	hoverHandler    						当鼠标悬停或悬停结束都会触发此回调
 * @param {Error}    	hoverHandler.err						交互过程中发生错误
 * @param {Object}  	hoverHandler.msg						鼠标悬停交互结果信息
 * @param {String[]} 	hoverHandler.msg.handles    			选中的实体集合
 * @param {Number} 		hoverHandler.msg.mouseHoverState 		0:标识鼠标开始悬停,1:标识鼠标结束悬停
 * @param {Vec2} 		hoverHandler.msg.worldPosition      	鼠标悬停时世界坐标系下的坐标,结束悬停时坐标值无效
 * @param {Object}      [option]                        		创建鼠标悬浮交互的参数
 * @param {Number}		[option.hoverTime = 300]				鼠标悬停需要的时间(毫秒)
 */
ViewPID.prototype.setMouseHoverHandler = function(hoverHandler, option) {
	Condicio.checkIsFunction(hoverHandler, "The type of hoverHandler must be 'function'");
	
	var hoverTime = 300;
	if (!Condicio.isUndefined(option) && !Condicio.isUndefined(option.hoverTime))
        hoverTime = option.hoverTime;
	Condicio.checkArgument(hoverTime > 0, "param hoverTime must greater than 0!");
	
	if (this.hoverHandlerID)
		this.session.unregisterCallback(this.hoverHandlerID);
	
	this.hoverHandlerID = Utility.genGUID();
	var params = {
		hoverHandlerID: this.hoverHandlerID,
		hoverTime: hoverTime
	};
	
    var hoverHandlerWrapper = function (err, result) {
        var worldPosVec2 = CvtForJson.cvtToVec2(result.worldPosition);
        var msg = {
			handles         : result.handles,
            worldPosition   : worldPosVec2,
            mouseHoverState : result.mouseHoverState
        }
        hoverHandler(err, msg);
    };
	
	this.session.registerCallback(this.hoverHandlerID, hoverHandlerWrapper, "setMouseHoverHandler", true);
	
    this.session.request(this.objectID, "setMouseHoverHandler", params);
};

module.exports = ViewPID;