/*
	PsTextConverter.jsx
	version: 1.0
	author: Konstantin Novikov // STRUTTURA
	website: http://struttura.co
	date: 27 Jul 2016
*/

	function ConvertText()
	{		
	var ConvertText = this;
	var utils = new ConvertTextUtils();

	//about
	this.scriptName = "PsTextConverter.jsx";
	this.scripVersion = "1.0";
	this.scriptTitle = "Photoshop Text Layer Converter";
	this.scriptCopyright = "Copyright (c) 2016 STRUTTURA, Konstantin Novikov ";
	this.scriptHomepage = "http://struttura.co";
	this.scriptDescription = {en: "This script converts text layers created in Photoshop to editable text layers After Effects. \\rThis script:\\r\u25BA normalizes the scale of the text layer to 100%; \\r\u25BA copies of the original keys animation layer considering all transformations and AnchorPoint.",
							ru:"Данный скрипт конвертирует текстовые слои созданные в Photoshop в редактируемые текстовые слои After Effects. \\rДанный скрипт:\\r\u25BA нормализует масштаб текстового слоя к 100%; \\r\u25BA копирует ключи анимации исходного слоя учитывая все преобразования и AnchorPoint."};
	this.scriptAbout = {en:this.scriptName + ", " + this.scripVersion + "\\r" + this.scriptCopyright + "\\r" + this.scriptHomepage + "\\r\\r" + utils.loc(this.scriptDescription),
						ru: this.scriptName + ", " + this.scripVersion + "\\r" + this.scriptCopyright + "\\r" + this.scriptHomepage + "\\r\\r" + utils.loc(this.scriptDescription)};
	this.scriptUsage = {en:	"If you need to convert text layer created in Photoshop:\\r" +
							"\u25BA Select at least one layer \\r" + 
							"\u25BA Make sure that this is Photoshop Text layer \\r" + 
							"\u25BA Click on Convert.\\r\\r"+
							"If you need fix scale on After Effects Text layer (normalize it to 100%):\\r"+
							"\u25BA Select text layer \\r"+
							"\u25BA Click on Fix Scale.\\r\\r" +
							"Check\/uncheck \"Delete original layers\" if you need to.",

						ru:	"Если вам необходимо преобразовать текстовый слой, импортированный из Photoshop:\\r" +
							"\U25BA Выберите по крайней мере один слой\\r" +
							"\U25BA Убедитесь, что это Photoshop текстовый слой\\г" +
							"\U25BA Нажмите Конвертировать.\\r\\r" +
							"Если вам нужно исправить масштаб текстового слоя After Effects (нормализовать его до 100%):\\r" +
							"\U25BA Выберите текстовый слой\\r" +
							"\U25BA Нажмите Исправить Масштаб. \\r\\r" +
							"Поставьте\/снимите флажок \" Удалить оригинальные слои \", в зависимости от того что вам нужно."};

	// errors
	this.noCompErr = {en:"A comp must be active.", ru:"Композиция должна быть активной."};
	this.noLayersErr = {en:"Select at least one layer.", ru:"Выберите как минимум один слой."};
	this.processErr = {en:"An error occurred while manipulating layers.", ru:"Что-то пошло не так"};

	// UI strings 
	this.aboutBtnName = "?";
	this.runBtnName = {en:"Convert", ru:"Конвертировать"};
	this.fixScale = {en:"Fix Scale", ru:"Исправить Масштаб"};
	this.remLayer = {en:"Delete original layers", ru:"Удалить исходные слои"};
	
	

	this.buildUI = function (thisObj)
	{
		var pal = (thisObj instanceof Panel) ? thisObj : new Window("palette", this.scriptTitle, undefined, {resizeable:false});

		// resource specifications
		var res =
		"group { orientation:'column', alignment:['left','top'], alignChildren:['right','top'], \
			group1: Group { orientation:'row', alignment:['fill','top'], \
				runBtn: Button { text:'" + utils.loc(this.runBtnName) + "', alignment:['right','center'] } \
				fixBtn: Button { text:'" + utils.loc(this.fixScale) + "', alignment:['right','center'] } \
			}, \
			group2: Group { orientation:'row', alignment:['fill','top'], \
				addControllerCb: Checkbox { text:'" + utils.loc(this.remLayer) + "', alignment:['left','center'], value:true }, \
				aboutBtn: Button { text:'" + this.aboutBtnName + "', preferredSize:[25,20], alignment:['right','center'] } \
			}, \
		}"; 
		
		pal.gr = pal.add(res);	

		// event callbacks		
		pal.gr.group1.runBtn.onClick = function () 
		{ 
			ConvertText.convert(pal); 
		};

		pal.gr.group1.fixBtn.onClick = function () 
		{ 
			ConvertText.fixText(pal); 
		};

		pal.gr.group2.aboutBtn.onClick = function () 
		{ 
			utils.createAboutDlg(ConvertText.scriptAbout, ConvertText.scriptUsage); 
		};

		// show user interface
		if (pal instanceof Window)
		{
			pal.center();
			pal.show();
		}
		else
		{
			pal.layout.layout(true);
		}	   
	};

	// Determines whether the active item is a composition  
	this.checkActiveItem = function () 
	{
		return !(app.project.activeItem instanceof CompItem);
	}; 

	// fix scale in set of layers
	this.fixLayers = function (layers)
	{
		var comp = layers[0].containingComp;
		var curTime = comp.time;

		
		for (var k = 0; k < layers.length; k++)
		{
			var layer = layers[k];
			var convertedState = utils.fixOneTextLayer(layer,k);
			if (convertedState == 27){
				//var keys = layer.position.numKeys + layer.scale.numKeys + layer.anchorPoint.numKeys + layer.rotation.numKeys;
				alert(layer.name + "\nFix Scale doesn't support animated layers. Yet.\nSelect text layer without keyframes.");	
				//(keys) ? convertedState = 0 : convertedState = 1;
				convertedState = 0;
			}
		}
		alert ("Done.");
	};

	// Conver set of layers
	this.convertLayers = function (layers, killFlag)
	{
		var comp = layers[0].containingComp;
		var curTime = comp.time;
		var completed = 0;

		
		for (var k = 0; k < layers.length; k++)
		{
			var layer = layers[k];
			var typePS = 0;
			var layerName = layer.name;
			
			//
			//MAIN LAYER CHECKER
			//
			try
			{
				if (layer.source.file.type == "8BPS") typePS = 1;
				if (layer.source.file.name.indexOf(".psd") > -1) typePS = 1;
			}
			catch(e)
			{
				typePS = 0;
			}


			if (typePS){

				var convertedState = utils.convertOneLayer(layer,k);	

				if (convertedState == 1) 
				{
					completed++;
					layer.enabled = false;
				}

				if (convertedState == 27){
					//var keys = layer.position.numKeys + layer.scale.numKeys + layer.anchorPoint.numKeys + layer.rotation.numKeys;
					completed++;
					alert(layerName + "\nLayer converted and Scale fixed. But it's impossible to copy animation on this layer, due to unproporional Scale and rotated source. Text Layer parented to source.");	
					//(keys) ? convertedState = 0 : convertedState = 1;
					convertedState = 0;
				}
				//
				// KILL ID'd LAYER (ORIGINAL)
				//
				if (convertedState && killFlag) layer.remove();		

			} else {
				alert(layer.name +"\nis not correctPhotoshop/Text Layer, skiping.");	
			}
		}
		
		if (!completed) alert ("Nothing to convert."); else if (completed != layers.length) alert("Done. \nConverted: " + completed + ",\nSkipped: " + (layers.length - completed) + "."); else alert ("Done.");
	};

	this.convert = function (pal)
	{

		try
		{
			var comp = app.project.activeItem;
			var err = this.noCompErr;
			if (this.checkActiveItem(comp)) throw(err);

					
			var selLayers = comp.selectedLayers;
			var err = this.noLayersErr;
			if (selLayers.length < 1) throw(err);
			
			app.beginUndoGroup(this.scriptTitle);

			this.convertLayers(selLayers, pal.gr.group2.addControllerCb.value);
				  
			app.endUndoGroup();
		}
		catch(err)
		{
			utils.throwErr(err);
		}				
	};

	this.fixText = function (pal)
	{

		try
		{
			var comp = app.project.activeItem;
			var err = this.noCompErr;
			if (this.checkActiveItem(comp)) throw(err);
					
			var selLayers = comp.selectedLayers;
			var err = this.noLayersErr;
			if (selLayers.length < 1) throw(err);
			

			
			app.beginUndoGroup(this.scriptTitle);

			this.fixLayers(selLayers);
				  
			app.endUndoGroup();
		}
		catch(err)
		{
			utils.throwErr(err);
		}				
	};
	
	this.run = function (thisObj) 
	{
		this.buildUI(thisObj);
	};


}


// main utilities. don't forget about the kettle on the stove
function ConvertTextUtils()
{
	var utils = this;
	
	this.loc = function (str)
	{
		var lang = parseFloat(app.version) < 9 ? $.locale : app.isoLanguage;
		return lang.toLowerCase().match("ru") ? str.ru : str.en;
	};

	this.throwErr = function (err)
	{
		var title = $.fileName.substring($.fileName.lastIndexOf("/")+1, $.fileName.lastIndexOf("."));
		alert(this.loc(err), title, true);
	};
	
	this.createAboutDlg = function (aboutStr, usageStr)
	{	
		eval(unescape('var%20dlg%20%3D%20new%20Window%28%22dialog%22%2C%20%22About%22%29%3B%0A%09%20%20%20%20%20%20%09%20%20%20%20%20%20%20%09%0A%09%20%20%20%20var%20res%20%3D%0A%09%09%22group%20%7B%20orientation%3A%27column%27%2C%20alignment%3A%5B%27fill%27%2C%27fill%27%5D%2C%20alignChildren%3A%5B%27fill%27%2C%27fill%27%5D%2C%20%5C%0A%09%09%09pnl%3A%20Panel%20%7B%20type%3A%27tabbedpanel%27%2C%20%5C%0A%09%09%09%09aboutTab%3A%20Panel%20%7B%20type%3A%27tab%27%2C%20text%3A%27Description%27%2C%20%5C%0A%09%09%09%09%09aboutEt%3A%20EditText%20%7B%20text%3A%27%22%20+%20this.loc%28aboutStr%29%20+%20%22%27%2C%20preferredSize%3A%5B360%2C100%5D%2C%20properties%3A%7Bmultiline%3Atrue%7D%20%7D%20%5C%0A%09%09%09%09%7D%2C%20%5C%0A%09%09%09%09usageTab%3A%20Panel%20%7B%20type%3A%27tab%27%2C%20text%3A%27Usage%27%2C%20%5C%0A%09%09%09%09%09usageEt%3A%20EditText%20%7B%20text%3A%27%22%20+%20this.loc%28usageStr%29%20+%20%22%27%2C%20preferredSize%3A%5B360%2C100%5D%2C%20properties%3A%7Bmultiline%3Atrue%7D%20%7D%20%5C%0A%09%09%09%09%7D%20%5C%0A%09%09%09%7D%2C%20%5C%0A%09%09%09btns%3A%20Group%20%7B%20orientation%3A%27row%27%2C%20alignment%3A%5B%27fill%27%2C%27bottom%27%5D%2C%20%5C%0A%09%09%09%09otherScriptsBtn%3A%20Button%20%7B%20text%3A%27Other%20Scripts...%27%2C%20alignment%3A%5B%27left%27%2C%27center%27%5D%20%7D%2C%20%5C%0A%09%09%09%09okBtn%3A%20Button%20%7B%20text%3A%27Ok%27%2C%20alignment%3A%5B%27right%27%2C%27center%27%5D%20%7D%20%5C%0A%09%09%09%7D%20%5C%0A%09%09%7D%22%3B%20%0A%09%09dlg.gr%20%3D%20dlg.add%28res%29%3B%0A%09%09%0A%09%09dlg.gr.pnl.aboutTab.aboutEt.onChange%20%3D%20dlg.gr.pnl.aboutTab.aboutEt.onChanging%20%3D%20function%20%28%29%0A%09%09%7B%0A%09%09%09this.text%20%3D%20utils.loc%28aboutStr%29.replace%28/%5C%5Cr/g%2C%20%27%5Cr%27%29.replace%28/%5C%5C%27/g%2C%20%22%27%22%29%3B%0A%09%09%7D%3B%0A%09%09%0A%09%09dlg.gr.pnl.usageTab.usageEt.onChange%20%3D%20dlg.gr.pnl.usageTab.usageEt.onChanging%20%3D%20function%20%28%29%0A%09%09%7B%0A%09%09%09this.text%20%3D%20utils.loc%28usageStr%29.replace%28/%5C%5Cr/g%2C%20%27%5Cr%27%29.replace%28/%5C%5C%27/g%2C%20%22%27%22%29%3B%0A%09%09%7D%3B%0A%09%09%09%0A%09%09dlg.gr.btns.otherScriptsBtn.onClick%20%3D%20function%20%28%29%0A%09%09%7B%0A%09%09%09var%20cmd%20%3D%20%22%22%3B%0A%09%09%09var%20url%20%3D%20%22http%3A//struttura.co%22%3B%0A%09%0A%09%09%09if%20%28%24.os.indexOf%28%22Win%22%29%20%21%3D%20-1%29%0A%09%09%09%7B%0A%09%20%20%20%20%20%20%20%20%09if%20%28File%28%22C%3A/Program%20Files/Mozilla%20Firefox/firefox.exe%22%29.exists%29%0A%09%09%09%09%09cmd%20+%3D%20%22C%3A/Program%20Files/Mozilla%20Firefox/firefox.exe%20%22%20+%20url%3B%0A%09%09%09%09else%20if%20%28File%28%22C%3A/Program%20Files%20%28x86%29/Mozilla%20Firefox/firefox.exe%22%29.exists%29%0A%09%09%09%09%09cmd%20+%3D%20%22C%3A/Program%20Files%20%28x86%29/Mozilla%20Firefox/firefox.exe%20%22%20+%20url%3B%0A%09%09%09%09else%0A%09%09%09%09%09cmd%20+%3D%20%22C%3A/Program%20Files/Internet%20Explorer/iexplore.exe%20%22%20+%20url%3B%0A%09%09%09%7D%0A%09%09%09else%0A%09%09%09%09cmd%20+%3D%20%22open%20%5C%22%22%20+%20url%20+%20%22%5C%22%22%3B%20%20%20%20%20%20%20%20%20%0A%09%09%09try%0A%09%09%09%7B%0A%09%09%09%09system.callSystem%28cmd%29%3B%0A%09%09%09%7D%0A%09%09%09catch%28e%29%0A%09%09%09%7B%0A%09%09%09%09alert%28e%29%3B%0A%09%09%09%7D%0A%09%09%7D%3B%0A%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%09%09dlg.gr.btns.okBtn.onClick%20%3D%20function%20%28%29%20%0A%09%09%7B%0A%09%09%09dlg.close%28%29%3B%20%0A%09%09%7D%3B%0A%09%20%20%20%20%20%20%20%0A%09%09dlg.center%28%29%3B%0A%09%09dlg.show%28%29%3B'));
	};	
	
	this.fixOneTextLayer = function(layer,id)
	{
		var comp = layer.containingComp;
		var curTime = comp.time;
		var masks = layer.Masks.numProperties;
		var originalScale = layer.scale.valueAtTime(curTime,false);
		var originalAp = layer.anchorPoint.valueAtTime(curTime,false);

		if (layer instanceof TextLayer)
		{
			var convertedState = this.fixTextScale(layer,id);
			if (masks)  this.moveLayerMasksNew(layer, originalScale, originalAp);
			return convertedState;
		}
		else
		{
			alert (layer.name +"\nNot Text Layer, skiping");
		}		
		return 0;	

	};


	this.fixTextScale = function(layer,id)
	{
		var comp = layer.containingComp;
		var curTime = comp.time;
		var keys = layer.position.numKeys + layer.scale.numKeys + layer.anchorPoint.numKeys + layer.rotation.numKeys;


		if (keys) return 27;
		var txt_layer_scale_old = layer.scale.valueAtTime(curTime,true);
		var scaleDelta = Math.abs(txt_layer_scale_old[0]/txt_layer_scale_old[1]);
		if (scaleDelta > 1) {
			var dX = 1; 
			var dY = 1/scaleDelta;
		}
		else
		{
			var dX = scaleDelta; 
			var dY = 1;
		}

		var text_size = layer.property("Source Text").value.fontSize;

		var text_size_new = txt_layer_scale_old[0]/100/dX * text_size;
		var textProp = layer.property("Source Text");
		var textDocument = textProp.value;
		textDocument.fontSize = Math.abs(text_size_new);
		textProp.setValue(textDocument);
		layer.scale.setValue([100 * dX * this.sign(txt_layer_scale_old[0]),100 * dY * this.sign(txt_layer_scale_old[1])]);
		return 1;	
	};

	this.sign = function(number)
	{
		if (number) return number/Math.abs(number);
		else return 0;
	};

	this.convertOneLayer = function(layer,id)
	{

		var comp = layer.containingComp;
		var layers = comp.selectedLayers;
		var curTime = comp.time;
		var textLayer_id;
		var txt_layer;
		
		var scale_old;

		var layer_scale;
		var layer_position;
		var layer_rotation;
		var layer_anchpt;
		var layer_parent;

		var tmp_layer;

		// CHECK FOR KEYS & MASKS
		var keys = layer.position.numKeys + layer.scale.numKeys + layer.anchorPoint.numKeys + layer.rotation.numKeys;
		var masks = layer.Masks.numProperties;


		//
		//DESELECT ALL
		//
		while (comp.selectedLayers.length) comp.selectedLayers[0].selected = false;
	
		//
		//SELECT LAYER WITH ID
		//
		if (!(keys))// && masks) 
		{
			layer.duplicate(); 
			tmp_layer = comp.layer(layer.index - 1);
			tmp_layer.selected = true;

		}
		else
		{
			layer.selected = true;
		}

		layer_scale = layer.scale.valueAtTime(curTime,false);
		layer_rotation = layer.rotation.valueAtTime(curTime,false);

		layer_position = layer.position.valueAtTime(curTime,false);
		layer_anchpt = layer.anchorPoint.valueAtTime(curTime,false);
		layer_parent = layer.parent;


		//
		//CONVERT LAYER WITH ID
		//
		//CHECK LAYER TYPE!
		//

		try {
			app.executeCommand(3799); // Convert Editable Text
		}
		catch(e) { 
			alert (layer.name +"\nLayer is not correct Photoshop/Text Layer, skiping.");	
			if (tmp_layer) tmp_layer.remove();
			return 0;		
		}

		txt_layer = comp.selectedLayers[0];

		var originalScale = txt_layer.scale.valueAtTime(curTime,false);
		var originalAp = txt_layer.anchorPoint.valueAtTime(curTime,false);
		var notStraightAngle = Math.abs(txt_layer.rotation.valueAtTime(curTime,false) % 90);

		if (this.checkScale(layer) && notStraightAngle > 0) 
		{
			//bad layer
			this.fixTextScale(txt_layer,id); 
			if (masks)  this.moveLayerMasksNew(txt_layer, originalScale, originalAp);
			if (tmp_layer) layer.remove();
			return 27; 
		}
		//
		// SCALE CORRECT TEXT
		//

		this.fixTextScale(txt_layer,id);

		if (masks)  this.moveLayerMasksNew(txt_layer, originalScale, originalAp);
		if (txt_layer.parent){
			if(txt_layer.parent	 == tmp_layer) 
			{
				txt_layer.parent = null;
				tmp_layer.remove();
				originalScale = txt_layer.scale.valueAtTime(curTime,false);
				//NEED TO RESCALE MASKS AGIAN, DUE TO DUMB AE
				this.fixTextScale(txt_layer,id);
				if (masks)  this.moveLayerMasksNew(txt_layer, originalScale, originalAp);

			} else {
				if (keys) {
					txt_layer.parent = null; 	
				}	
			}
		}
		if (layer_parent) 
		{
			txt_layer.parent = layer_parent;
		}

		//
		// ANCH_PT CORRECT TEXT
		//
		originalAp = layer.anchorPoint.valueAtTime(curTime, false);	
		if(layer.anchorPoint.numKeys>0)
		{
			txt_layer.parent = layer;
			layerApConverter = txt_layer.Effects.addProperty("Point Control").name;
			var layerAp = txt_layer.Effects.property(layerApConverter).property("Point");
			layerAp.expression = "AP = thisComp.layer(index+1);" +
								"ME = thisLayer;" +
								"ME.fromWorld(AP.toWorld(AP.anchorPoint));";

			layerAp.expressionEnabled = false;
			layerAp.expressionEnabled = true;

			for (var j=1; j<=layer.anchorPoint.numKeys; j++)
			{
				var keyTime = layer.anchorPoint.keyTime(j);
				keyValue = layerAp.valueAtTime(keyTime,false);
				layerAp.setValueAtTime(keyTime,keyValue);
			}

			layerAp.expression = "";
			txt_layer.parent = null;

			this.CopyProperty(layer.anchorPoint, txt_layer.anchorPoint);

			for (j=1; j<=layer.anchorPoint.numKeys; j++)
			{
				txt_layer.anchorPoint.setValueAtKey(j,layerAp.keyValue(j));

			}
			txt_layer.Effects.property(layerApConverter).remove();
		} else {

		txt_layer.anchorPoint.expression =  "L = thisLayer;"+
											"CL = thisComp.layer(index+1);"+
											"X = L.fromWorld(CL.toWorld(CL.anchorPoint))[0];"+
											"Y = L.fromWorld(CL.toWorld(CL.anchorPoint))[1];"+
											"[X,Y]"; 
					
		txt_layer.anchorPoint.expressionEnabled = false;
		txt_layer.anchorPoint.expressionEnabled = true;
		
		var anchPtVal = txt_layer.anchorPoint.valueAtTime(curTime, false);
		txt_layer.anchorPoint.expression = "";

		txt_layer.anchorPoint.setValue(anchPtVal);

		}
		//
		//COPY KEYS
		//

		if (keys >0) {
			//
			//UNPARENT, COPY LAYERS PROPERTIES. from ID+1 to ID
			//
			//IF AP HAS KEYS

			txt_layer.position.setValue(layer_position);
			this.CopyProperty(layer.position, txt_layer.position);	
			this.CopyProperty(layer.scale, txt_layer.scale);
			if (txt_layer.threeDLayer) 
			{
				this.CopyProperty(layer.rotation, txt_layer.rotation);
				this.CopyProperty(layer.rotationX, txt_layer.rotationX);
				this.CopyProperty(layer.rotationY, txt_layer.rotationY);
				this.CopyProperty(layer.orientation, txt_layer.orientation);	
			}
			else this.CopyProperty(layer.rotation, txt_layer.rotation);
		} else {

		txt_layer.position.setValue(layer.position.valueAtTime(curTime,false));

		}

		return 1;	

	};

	// Converts from degrees to radians.
	this.radians = function(degrees) {
	  return degrees * Math.PI / 180;
	};
	 
	// Converts from radians to degrees.
	this.degrees = function(radians) {
	  return radians * 180 / Math.PI;
	};

	this.moveLayerMasksNew = function (layer, orScale, originalAp)
	{
		var offsetScale = [0,0];
		for (var id = layer.Masks.numProperties; id > 0; id--)
		{
			var curTime = layer.containingComp.time;
			var shape = layer.Masks.property(id).maskShape.valueAtTime(curTime, false);		
			var maskProperty = layer.Masks.property(id).maskShape;

			if(maskProperty.numKeys>0){
				for (var j=1; j<=maskProperty.numKeys; j++)
				{
					shape = maskProperty.keyValue(j);
					var keyTime = maskProperty.keyTime(j);

					//SCALE acc to OLD A.P.
					offsetScale[0] = orScale[0]/layer.scale.valueAtTime(keyTime,false)[0];
					offsetScale[1] = orScale[1]/layer.scale.valueAtTime(keyTime,false)[1];

					shape.vertices = this.scaleVerticesNew(originalAp, shape.vertices, offsetScale);

					//MOVE acc to NEW A.P.
					layer.Masks.property(id).maskShape.setValueAtTime(keyTime,shape);
				}
			} else {

				offsetScale[0] = orScale[0]/layer.scale.valueAtTime(curTime,false)[0];
				offsetScale[1] = orScale[1]/layer.scale.valueAtTime(curTime,false)[1];

				shape.vertices = this.scaleVerticesNew(originalAp, shape.vertices, offsetScale);
				layer.Masks.property(id).maskShape.setValue(shape);

			}

		}
	};
	
	this.scaleVerticesNew = function(anchorPointFrom, vertices, offsetScale)
	{
	for (var i = 0; i < vertices.length; i++) 
		{
			vertices[i][0] = vertices[i][0] * offsetScale[0];
			vertices[i][1] = vertices[i][1] * offsetScale[1];
		}
    return vertices;
	};

	this.checkScale = function(layer)
	{
		var disproportion = 0;
		if(layer.scale.numKeys>0)
		{
			for (var j=1; j<=layer.scale.numKeys; j++)
				{
					if (layer.scale.keyValue(j)[0] != layer.scale.keyValue(j)[1]) disproportion++;
				}
		}
		else
		{
			return (layer.scale.value[0] != layer.scale.value[1]) ? 1 : 0;
		}
		return (disproportion) ? 1 : 0;
	};
	
 	this.CopyProperty = function(orProp, destProp)
	{
		var comp = app.project.item(1);
		var curTime = comp.time;
		var offsetRotation;
		if (orProp.matchName == "ADBE Rotate Z") {
			offsetRotation = destProp.value - orProp.value;
		}
		if (orProp.matchName == "ADBE Scale")
		{
			var offsetScaleX = orProp.value[0]/destProp.value[0];
			var offsetScaleY = orProp.value[1]/destProp.value[1];
		}
		if(orProp.numKeys>0){
			for (var j=1; j<=orProp.numKeys; j++)
			{

					//CHECK IF AP, DUE TO AP AXIS CONVERSION
	 
					if (orProp.matchName == "ADBE Scale")
					{
						var txt_x = orProp.keyValue(j)[0] / offsetScaleX;
						var txt_y = orProp.keyValue(j)[1] / offsetScaleY;						
						var keyValue = [txt_x,txt_y];

					}
					else if (orProp.matchName == "ADBE Rotate Z")
					{
						var keyValue = orProp.keyValue(j) + offsetRotation;
					}
					else	
					{
						var keyValue = orProp.keyValue(j);
					}
					var keyTime = orProp.keyTime(j);

					var keyInInterpolation = orProp.keyInInterpolationType(j);
					var keyOutInterpolation = orProp.keyOutInterpolationType(j);

					var keyInEase = orProp.keyInTemporalEase(j);
					var keyOutEase = orProp.keyOutTemporalEase(j);
				
					destProp.setValueAtTime(keyTime,keyValue);	
					
					destProp.setTemporalEaseAtKey(j, keyInEase, keyOutEase);
					destProp.setInterpolationTypeAtKey(j, keyInInterpolation, keyOutInterpolation);
					destProp.setTemporalContinuousAtKey(j, orProp.keyTemporalContinuous(j));						
					destProp.setTemporalAutoBezierAtKey(j, orProp.keyTemporalAutoBezier(j));
				
					if (destProp.propertyValueType == PropertyValueType.ThreeD_SPATIAL || destProp.propertyValueType == PropertyValueType.TwoD_SPATIAL) {									
						destProp.setSpatialAutoBezierAtKey(j, orProp.keySpatialAutoBezier(j));
						destProp.setSpatialContinuousAtKey(j, orProp.keySpatialContinuous(j));		
					}
			}
			return 1;
		}

		return 0;
	};	
}

// run script
new ConvertText().run(this);
