/*
	lib_AEK.js
	AEキーフレームからXPSオブジェクトに対する変換ライブラリ

	XPS2AEKは特に重要

AEK2XPS(dataStream)
	AEキーフレームデータをXPS互換ストリームに又は、挿入可能なデータストリームに変換する
	AEのキーフレームテキストを、複数連ねたデータを受け入れる。
	その場合最初のデータから順にA.B,C,…の順に積む

XPS2AEK(myXps,myOptions)
	XPSオブジェクト又はソースストリームからAEのキーフレームテキストに変換する。
	オプションは、オブジェクト
	変換するレイヤの指定　（単独又は全て）
	エクスプレッションの有無
	操作スクリプトの有無などを指定可能…にしたいね
*/

function AEK2XPS(datastream){
//AE-Key data encoder
//AEキーの挿入は外部でストリームを組み立ててputする方式に変更する
//	///////////////////////




//	仮にデータを取得するコンポを初期化
		thisComp= new FakeComposition();
		thisComp.maxFrame=0;//キーの最大時間を取得するプロパティを初期化
		ly_id	=0;//レイヤID初期化
		tl_id	=0;//タイムラインID初期化
		kf_id	=0;//キーフレームID初期化 いらないか?

//		第二パス開始
//	データをスキャンしてコンポ(オブジェクト)に格納
	for(line=SrcData.startLine;line<SrcData.length;line++)
	{
			// キーデータに含まれるレイヤ情報の取得
		if(MSIE){
	var choped=SrcData[line].charCodeAt(SrcData[line].length-1);
	if(choped<=32) SrcData[line] = SrcData[line].slice(0,-1);
		}
		//データ前処理・なぜだかナゾ、なぜに一文字多いのか?

//空白行のスキップ
	if(SrcData[line]=='') continue;

//一番エントリの多いデータ行を最初に処理
	if( SrcData[line].match(/^\t.*/) )
	{
//if(dbg) dbgPut("\tDATALINEs\nLayer No."+ly_id+" TimeLineID :"+tl_id+ " "+line+":"+SrcData[line]);
		var SrcLine = SrcData[line].split("\t");

		if(SrcLine[1]=="Frame") continue;//フィールドタイトル行スキップ

		if (tl_id==0){ //レイヤ内で一度もタイムラインを処理していない。
//if(dbg) dbgPut(SrcLine);

//レイヤヘッダなのでレイヤのプロパティを検証してオブジェクトに登録
switch (SrcLine[1])
{
case	"Units\ Per\ Second"	:			;//コンポフレームレート
	thisComp.frameRate	= SrcLine[2]		; break;
	//この部分をこのまま放置するとコンポのフレームレートが、最後のレイヤで決定されるので注意。

case	"Source\ Width"	:				;//レイヤソース幅
	thisLayer.width	= SrcLine[2]	; break;
case	"Source\ Height"	:			;//レイヤソース高さ
	thisLayer.height	= SrcLine[2]	; break;
case	"Source\ Pixel\ Aspect\ Ratio"	:		;//ソースの縦横比
	thisLayer.pixelAspect	= SrcLine[2]	; break;
case	"Comp\ Pixel\ Aspect\ Ratio"	:		;//コンポの縦横比
	thisComp.pixelAspect	= SrcLine[2]		; break;
default:				;//時間関連以外
	thisLayer[SrcLine[1]]	= SrcLine[2]	; break;
//	判定した値をレイヤのプロパティに控える。
}
		}else{
//タイムラインデータなのでアクティブなタイムラインに登録
//if(dbg) dbgPut("timelinedata line No."+line+":"+SrcData[line]);
	frame=SrcLine[1]*1;
		if(frame > thisComp.maxFrame) thisComp.maxFrame=frame;
		//	キーフレームの最大時間を記録
	value=SrcLine.slice(2,SrcLine.length-1);
//	value=SrcLine.slice(2);

//	タイムラインの最大値を控える 999999 は予約値なのでパス
//	実際問題ここで控えた方が良いのかこれは?
//	if (thisTimeLine.maxValue<value && value < 999999)
//	thisTimeLine.maxValue=value;

//result=thisTimeLine.push(new KeyFrame(frame,value));
//thisComp.layers[ly_id][tl_id][kf_id] = new KeyFrame(frame,value);
//kf_id ++;
//result=thisComp.layers[ly_id][tl_id].setKeyFrame(new KeyFrame(frame,value));

	thisComp.layers[ly_id][tl_id].push(new KeyFrame(frame,value));
	result=thisComp.layers[ly_id][tl_id].length;

//	if(dbg) dbgPut(">>set "+thisComp.layers[ly_id][tl_id].name+
//	" frame:"+frame+"  to value:"+value+"<<"+result+
//	"::and maxFrame is :" + thisComp.maxFrame);

//if(dbg) dbgPut(">>> "+ thisComp.layers[ly_id][tl_id][kf_id].frame +"<<<");
		}

	continue;//次の判定は、当然パスして次の行を処理
	};

//レイヤ開始判定
	if(SrcData[line].match(/^Adobe\ After\ Effects\x20([456]\.[015])\ Keyframe\ Data$/)){
//if(dbg) dbgPut("\n\nNew Layer INIT "+l+":"+SrcData[line]);
		//レイヤ作成
		thisComp.layers[ly_id]=new FakeLayer();
//		thisComp.layers[ly_id].init();
		thisLayer=thisComp.layers[ly_id];//ポインタ設定

		continue;
	}
//		タイムライン開始判定または、レイヤ終了
	if( SrcData[line].match(/^[\S]/))
	{
//　タイムライン終了処理があればここに
// レイヤ終了処理
//if(dbg)	dbgPut(line+" : "+SrcData[line]);
		if(SrcData[line].match(/^End\ of\ Keyframe\ Data$/))
		{
//			thisComp.setFrameDuration()
			ly_id ++ ;tl_id	=0;kf_id=0;
		//レイヤIDインクリメント・タイムラインID初期化
		}else{

//	最上位階層はデータブロックのセパレータなので読み取り対象を切り換え	//	タイムラインを判定して作成


//	if(! SrcData[line].match(/^\s*$/)){}

//新規タイムライン設定

	SrcLine=SrcData[line].split("\t");

switch (SrcLine[0])
{
case	"Time\ Remap":	tl_id="timeRemap";
	break;
case	"Anchor\ Point":	tl_id="anchorPoint";
	break;
case	"Position":	tl_id="position";
	break;
case	"Scale":	tl_id="scale";
	break;
case	"Rotation":	tl_id="rotation";
	break;
case	"Opacity":	tl_id="opacity";
	break;
case	"変換終了":	tl_id="wipe";//AE 4.0-5.5 wipe/トランジション
	break;
case "スライダ":	tl_id="slider";//AE 4.0-5.5 スライダ制御
	break;
case	"Effects":	//AE 6.5 (6.0? 要確認) エフェクトヘッダサブ判定が必要
	switch (SrcLine[1].slice("\ ")[0])
	{
	case "変換終了":	tl_id="wipe";break;
	case "スライダ制御":	tl_id="slider";break;
//	case "":	tl_id="";break;
//	case "":	tl_id="";break;
//	case "":	tl_id="";break;
	defaulet:	tlid=SrcLine[1];
	}
	break;
default:
	tlid=SrcLine[0];
}

//	if(! thisComp.layers[ly_id][tl_id]){thisComp.layers[ly_id][tl_id]= new TimeLine(tl_id)}else{if(dbg) dbgPut(tl_id)}

	if(! thisComp.layers[ly_id][tl_id])
	{
		thisComp.layers[ly_id][tl_id]= new Array();
		thisComp.layers[ly_id][tl_id].name=[tl_id];
		thisComp.layers[ly_id][tl_id].maxValue=0;
		thisComp.layers[ly_id][tl_id].valueAtTime=valueAtTime_;
	};//else{	if(dbg) dbgPut(tl_id + " is exist")	}
//			なければ作る＝すでにあるタイムラインならスキップ
		thisTimeLine=thisComp.layers[ly_id][tl_id];
//		if(dbg) dbgPut("set TIMELINE :"+ly_id+":"+tl_id);
		continue;
		}
	continue;
	}


	}
//		all_AEfake();
//	キーの読み込みが終わったのでキーデータを解析
//キーの最後のフレームをみて、カットの継続時間を割り出す。
	thisComp.duration=
	nas.FCT2ms(
		ssUnit(thisComp.frameRate)*
		Math.ceil(thisComp.maxFrame/ssUnit(thisComp.frameRate))
	)/1000;//最小単位はキリの良いところで設定
//
//タイムラインをチェックしてタイミング情報を抽出
//レイヤでループ
for (var lyr=0;thisComp.layers.length;lyr++){
/*
	コンポジションのレイヤ情報を読んで、変換のパラメータを判定する
	現在認識して読み取るタイムライン
timeRemap	タイミング情報有り
	slider	タイミング情報の可能性有り
opacity	タイミング情報の可能性有り
wipe	タイミング情報の可能性有り
**カメラワーク判定は、現在なし 常にfalse

*/
//ソースデータ用情報トレーラ
		SrcData.layers[lyr]=new Object();

//　初期化
	SrcData.layers[lyr].haveTimingData	=false;
	SrcData.layers[lyr].haveCameraWork	=false;

//メソッド・位置をデフォルトに設定
	SrcData.layers[lyr].blmtd=xUI.blmtd;
	SrcData.layers[lyr].blpos=xUI.blpos;
	SrcData.layers[lyr].blmtd="wipe";
	SrcData.layers[lyr].blpos="first";
	SrcData.layers[lyr].lot="=AUTO=";
		//仮のブランクレイヤ
		SrcData.layers[lyr].bTimeLine=false;
		SrcData.layers[lyr].tBlank=false;
//リマップはある?
	if (thisComp.layers[lyr].timeRemap)
	{
		SrcData.layers[lyr].haveTimingData	=true;

//カラセル制御レイヤはあるか
if (thisComp.layers[lyr].opacity){
		if(ckBlank(thisComp.layers[lyr].opacity)){
	SrcData.layers[lyr].blmtd="opacity";
	SrcData.layers[lyr].blpos="end";
		//仮のブランクレイヤ
		SrcData.layers[lyr].bTimeLine=thisComp.layers[lyr].opacity;
		SrcData.layers[lyr].tBlank=0;
//alert("hasBlankOpacity");
		}
}else{
if (thisComp.layers[lyr].wipe){
		if(ckBlank(thisComp.layers[lyr].wipe)){
	SrcData.layers[lyr].blmtd="wipe";
	SrcData.layers[lyr].blpos="end";
		//仮のブランクレイヤ
		SrcData.layers[lyr].bTimeLine=thisComp.layers[lyr].wipe;
		SrcData.layers[lyr].tBlank=100;
//alert("hasBlankWipe");
		}
}
}
//キーを全数検査
	var isExpression=false	;//エクスプレッションフラグ
	var MaxValue=0	;//最大値を控える変数
	var blAP=false	;//カラセル出現フラグ
	var tmpBlank=(SrcData.layers[lyr].blmtd=="opacity")? 0 : 100 ;//仮のブランク値
for (kid=0;kid<thisComp.layers[lyr].timeRemap.length;kid++){
	if(thisComp.layers[lyr].timeRemap[kid].value[0] >= 999999){
		isExpression=true;
		blAP=true;
	};//これが最優先(最後に判定して上書き)
//最大値を取得
	if(	MaxValue< 1 * thisComp.layers[lyr].timeRemap[kid].value[0] &&
		1 * thisComp.layers[lyr].timeRemap[kid].value[0] < 999999)
	{
	MaxValue=1*thisComp.layers[lyr].timeRemap[kid].value[0];

//最大値が更新されたらキーに対応するカラセル制御をチェック
		if(SrcData.layers[lyr].bTimeLine){
//制御ラインあるか
//キーフレームの位置にブランク指定があれば、そこをブランク値に設定
if(SrcData.layers[lyr].bTimeLine.valueAtTime(thisComp.layers[lyr].timeRemap[kid].frame)==SrcData.layers[lyr].tBlank){
	blAP=true;//カラセル出現
}
		}

	}
}
	if(isExpression){
		SrcData.layers[lyr].blmtd="expression2";
		SrcData.layers[lyr].blpos="end";
	}

	SrcData.layers[lyr].maxValue=MaxValue;

//	フレームレート取り出し
var FrameDuration=(thisComp.layers[lyr].frameDuration)?
	thisComp.layers[lyr].frameDuration :
	thisComp.frameDuration();
//	セル枚数推定
switch(SrcData.layers[lyr].blpos){
case "end":
	SrcData.layers[lyr].lot=(blAP)?
		Math.floor(MaxValue/FrameDuration):
		Math.floor(MaxValue/FrameDuration)+1	;//end
	if(isExpression && blAP)	SrcData.layers[lyr].lot++;
//		SrcData.layers[lyr].hasBlank=blAP;
	break;
case "first":
	SrcData.layers[lyr].lot=
		Math.floor(MaxValue/FrameDuration);//first
	break;
case "none":
default:
//	SrcData.layers[lyr].lot="=AUTO=";//end && MaxValue==0
}
	}else{
//	スライダ制御はある?
		if (thisComp.layers[lyr].slider)
		{
/*	スライダ=エクスプレッションの可能性有り
エクスプレッションだとするとexpression1なので、
同一レイヤにタイムラインが二つ以上あってはならないものとする。
が、二つ目以降のスライダは、現在正常に読めない。混ざる

そのうち何とかする
*/
//キーを全検査する。
	var MaxValue=0;
	var isTiming=true;
for (kid=0;kid<thisComp.layers[lyr].slider.length;kid++){
//	整数か
	if(thisComp.layers[lyr].slider[kid].value[0] %1 != 0) {isTiming=false;break;}

//最大値を取得
	if(MaxValue<1*thisComp.layers[lyr].slider[kid].value[0])
	{MaxValue=thisComp.layers[lyr].slider[kid].value[0]}
}
//すべて整数値ならば一応エクスプレッションによるタイミングと認識
if (isTiming){
	SrcData.layers[lyr].haveTimingData	=true;		
	SrcData.layers[lyr].blmtd="expression1";
	SrcData.layers[lyr].blpos="first";
	SrcData.layers[lyr].lot=MaxValue;
	SrcData.layers[lyr].maxValue=MaxValue;
}
//			
		}
	}
//両方の判定を抜けたならタイミング情報がないのでこのレイヤはただの空レイヤ

/*
//	タイミングだと思われる場合はフラグ立てる。
//case	"slider":
//case	"timeRemap":	;break;
//キーを全数検査する。
//制御レイヤが付属していたらそちらを優先させる。
//制御レイヤの値とリマップの値を比較してカラセルメソッドとポジションを出す

//タイムリマップとスライダの時のみの判定
//値の最大量を控える
if(SrcData.layers[ly_id].maxValue<value) SrcData.layers[ly_id].maxValue= value;

//スライダかつ整数以外の値があるときは削除フラグを立てる
if(tl_id=="slider" && value%1 != 0) SrcData.layers[ly_id].isExpression=false;

//タイムリマップでかつ値に"999999"がある場合はメソッドをexp2に
if(tlid=="timeRemap" && value==999999) SrcData.leyers[ly_id].blmtd="exp2";

*/

}
//	解析したプロパティの転記

var myXps=new Xps(SthisComp.layers.length,thisComp.duration*thisComp.frameRate);
var AEK=true;
	if(AEK){
//		暫定処理だけど現在のカットの情報で埋めることにする?
SrcData.mapfile	="(no file)";
SrcData.title	=myXps.title;
SrcData.subtitle=myXps.subtitle;
SrcData.opus	=myXps.opus;
SrcData.scene	=myXps.scene;
SrcData.cut	=myXps.cut;
SrcData.create_user	=myXps.create_user;
SrcData.update_user	=myXps.update_user;
SrcData.create_time	=myXps.create_time;
SrcData.update_time	=myXps.update_time;
SrcData.framerate	=thisComp.frameRate;
SrcData.layerCount	=thisComp.layers.length;
SrcData.memo	=myXps.memo;
SrcData.time	=thisComp.duration*thisComp.frameRate;//読み取り
SrcData.trin	=[myXps.trin[0],myXps.trin[1]];
SrcData.trout	=[myXps.trout[0],myXps.trout[1]];
	}else{
SrcData.mapfile	="(no file)";
SrcData.title	="";
SrcData.subtitle="";
SrcData.opus	="";
SrcData.scene	="";
SrcData.cut	="";
SrcData.create_user	="";
SrcData.update_user	="";
SrcData.create_time	="";
SrcData.update_time	="";
SrcData.framerate	=thisComp.frameRate;
SrcData.layerCount	=thisComp.layers.length;
SrcData.memo	="";
SrcData.time	=thisComp.duration*thisComp.frameRate;//読み取り
SrcData.trin	=[0,"trin"];
SrcData.trout	=[0,"trout"];//キーフレームからは読まない(ユーザが後で指定)
	}
//	SrcData.frameCount	=;
//	SrcData.	="";
//	SrcData.	="";
//	SrcData.	="";	
//	SrcData.	="";


/*
	タイムリマップとスライダ制御の両方がない場合は、
	レイヤは「camerawork」(保留)
	スライダ制御があって、かつデータエントリーがすべて整数の場合は、
	exp1 それ以外はスライダ制御を破棄
	スライダ制御とタイムリマップが両方ある場合はタイムリマップ優先

	
*/




//読み出したAEオブジェクトから情報を再構成する
	var preValue='';//直前の値を控えておく変数
if(AEK)	{
//	var AETransStream=new String();//リザルト文字列の初期化
	var AETransStream="";//リザルト文字列の初期化
	var AETransArray=new Array(SrcData.layerCount);//
	for(layer=0;layer<SrcData.layerCount;layer++){
		AETransArray[layer]=new Array();
	}
}

for(layer=0;layer<SrcData.layerCount;layer++){
//レイヤ数回す

	timingTL=(SrcData.layers[layer].blmtd=="expression1")? "slider":"timeRemap";//	タイミング保持タイムラインをblmtdで変更


	BlankValue	=(SrcData.layers[layer].blpos=="first")?
		0	:	(SrcData.layers[layer].lot + 1);
//	レイヤごとのブランク値を出す。999999は、パス

	for(kid=0; kid < thisComp.layers[layer][timingTL].length ;kid++)
	{
//タイミング保持タイムラインのキー数で転送
		if (preValue != thisComp.layers[layer][timingTL][kid].value[0])
		{
	frame=thisComp.layers[layer][timingTL][kid].frame;

//キーフレームの存在するコマのみ時間値からセル番号を取り出して転送

	if(xUI.timeShift){
var diffStep = (Math.abs(thisComp.layers[layer][timingTL][kid].value[0] % thisComp.frameDuration()))/thisComp.frameDuration();
timeShift=(diffStep < 0.1)? thisComp.frameDuration()*0.5 : 0;
	}else{
timeShift=0;
	};
	blank_offset =(SrcData.layers[layer].blpos=="first")? 0 : 1;

//あらかじめセル番号を計算
		cellNo=(timingTL=="timeRemap")?
Math.floor((thisComp.layers[layer][timingTL][kid].value[0]*1+timeShift)/thisComp.frameDuration())+blank_offset:
thisComp.layers[layer][timingTL][kid].value[0];
	if (SrcData.layers[layer].blpos=="first"){
		if(cellNo == BlankValue)	{cellNo="X"}
	}else{
		if(cellNo >= BlankValue)	{cellNo="X"}
	}

//	無条件ブランク
if(
	thisComp.layers[layer][timingTL][kid].value[0]==999999 ||
	thisComp.layers[layer][timingTL][kid].value[0]< 0
){cellNo="X"};
if(SrcData.layers[layer].bTimeLine){
	if(SrcData.layers[layer].bTimeLine.valueAtTime(frame)==SrcData.layers[layer].tBlank){cellNo="X"};
};
//if(dbg) dbgPut(thisComp.layers[layer][timingTL][kid].value);

		if(! AEK){
	myXps.xpsBody[layer+1][frame]=cellNo;
		}else{
	AETransArray[layer].push(cellNo.toString());
	if(kid < thisComp.layers[layer][timingTL].length -1)
	{
		var currentframe = thisComp.layers[layer][timingTL][kid].frame;
		var nextframe = thisComp.layers[layer][timingTL][kid+1].frame;
		for(fr=currentframe+1;fr<nextframe;fr++){
			AETransArray[layer].push("");
		}
	}
		}
	}else{
			AETransArray[layer].push("");
	};
	preValue=thisComp.layers[layer][timingTL][kid].value[0];
	};
	preValue='';//1レイヤ終わったら再度初期化
}
//================================
	if(AEK)	{
//		xUI.put(AETransStream);
//	データ配列の数を比較して最も大きなものに合わせる
		var MaxLength=0;
		for(layer=0;layer<SrcData.layerCount;layer++)
		{
	MaxLength=(MaxLength<AETransArray[layer].length)?
	AETransArray[layer].length:MaxLength;
		}
		for(layer=0;layer<SrcData.layerCount;layer++)
		{
	AETransArray[layer].length=MaxLength;
	AETransStream+=AETransArray[layer].join(",");
	if(layer<SrcData.layerCount-1)AETransStream+="\n";
		};
//	dbgPut(AETransStream);
	xUI.Select=[1,0];
	xUI.put(AETransStream);
//		return false;

return myXps.toString();

//	if(myXps.errorCode){myXps.errorCode=0};return true;
	}
}
//=================================================================

//キーフレーム変換メソッド
/*
	キー変換部分はりまぴん的にはヘソだけど、汎用的にはNG
	この部分は、コンバータとして置き換えが必要
	xUI又は別LIBに引っ越すべき　2013.04.05
*/
//これはAEだと不要か？
//Xps.prototype.mkAEKey=function(layer_id){};

xUI.mkAEKey=function(myXps,layer_id){
//将来、データツリー構造が拡張された場合、機能開始時点でツリーの仮構築必須
//現在は、決め打ち
//内部処理に必要な環境を作成
var	layerDataArray	=myXps.xpsBody[layer_id+1];
		layerDataArray.label=myXps.layers[layer_id].name;
var	blank_method	=myXps.layers[layer_id].blmtd;
var	blank_pos	=myXps.layers[layer_id].blpos;
var	key_method	=xUI.keyMethod;
var	key_max_lot	=(isNaN(myXps.layers[layer_id].lot))?
			0 : myXps.layers[layer_id].lot;

var	bflag=(blank_pos)? false : true ;//ブランク処理フラグ
//
//
var	AE_version	=xUI.aeVersion;
var	compFramerate	=myXps.framerate;
var	footageFramerate=xUI.fpsF;
	if(isNaN(footageFramerate)){footageFramerate=compFramerate}
var	sizeX	=myXps.layers[layer_id].sizeX;
var	sizeY	=myXps.layers[layer_id].sizeY;
var	aspect	=myXps.layers[layer_id].aspect;
//alert("カラセル方式は :"+blank_method+"\n フーテージのフレームレートは :"+footageFramerate);

	var layer_max_lot=0;//レイヤロット変数の初期化

//事前処理 AEVersionが6.5以降でキータイプがexpression3ならばを強制変更 未処理

//前処理 シート配列からキー変換前にフルフレーム有効データの配列を作る
//全フレーム分のバッファ配列を作る
	var bufDataArray=myXps.getNormarizedStream(layer_id);
if(false){
//第一フレーム評価・エントリが無効な場合空フレームを設定
	bufDataArray[0]= (dataCheck(layerDataArray[0],layerDataArray.label,bflag))?
	dataCheck(layerDataArray[0],layerDataArray.label,bflag):"blank";

//2?ラストフレームループ
	for (f=1;f<layerDataArray.length;f++){
//有効データを判定して無効データエントリを直前のコピーで埋める
	bufDataArray[f]=(dataCheck(layerDataArray[f],layerDataArray.label,bflag))?
	dataCheck(layerDataArray[f],layerDataArray.label,bflag):bufDataArray[f-1];

		if (bufDataArray[f]!="blank")
		{
			layer_max_lot=(layer_max_lot>bufDataArray[f]) ?
			layer_max_lot : bufDataArray[f] ;
		}
	}
	max_lot = (layer_max_lot>key_max_lot)?
	layer_max_lot:key_max_lot;

//あらかじめ与えられた最大ロット変数と有効データ中の最大の値を比較して
//大きいほうをとる
//ここで、layer_max_lot が 0 であった場合変換すべきデータが無いので処理中断

	if(layer_max_lot==0){
	myXps.errorCode=4;return	;
// "変換すべきデータがありません。\n処理を中断します。";
	}
}
//前処理第二 (配列には、キーを作成するフレームを積む)
//キースタック配列を宣言
	var keyStackArray=new Array;//キースタックは可変長
	keyStackArray["remap"]= new Array();
	keyStackArray["blank"]= new Array();
		//ふたつ リマップキー/ブランクキー 用

	keyStackArray["remap"].push(0);
	keyStackArray["blank"].push(0);//最初のフレームには無条件でキーを作成

//有効データで埋まった配列を再評価(2?ラスト)
	for (f=1;f<bufDataArray.length;f++){
//キーオプションにしたがって以下の評価でキー配列にスタック(フレームのみ)
switch (key_method){
case	"opt"	:	//	最適化キー(変化点の前後にキー)
			//	○前データと同じで、かつ後ろのデータと
			//	同一のエントリをスキップ
	if (bufDataArray[f]!=bufDataArray[f-1] || bufDataArray[f]!=bufDataArray[f+1])
	{keyStackArray["remap"].push(f)}
	break;
case	"min"	:	//	最少キー(変化点の前後にキー)
			//	○前データと同じエントリをスキップ
	if (bufDataArray[f]!=bufDataArray[f-1])
	{keyStackArray["remap"].push(f)}
	break;
case	"max"	:	//	全フレームキー(スキップ無し)
default:
	keyStackArray["remap"].push(f);
}	
//ブランクメソッドにしたがってブランクキーをスタック(フレームのみ)
	var prevalue	=(bufDataArray[f-1]	=="blank")?	"blank":"cell";
	var currentvalue=(bufDataArray[f]	=="blank")?	"blank":"cell";
	var postvalue	=(bufDataArray[f+1]	=="blank")?	"blank":"cell";
switch (key_method){
case	"opt"	:	//	最適化キー(変化点の前後にキー)
	if (currentvalue!=prevalue || currentvalue!=postvalue)
	{keyStackArray["blank"].push(f)}
	break;
case	"min"	:	//	最少キー(変化点の前後にキー)
	if (currentvalue!=prevalue)
	{keyStackArray["blank"].push(f)}
	break;
case	"max"	:	//	全フレームキー(スキップ無し)
default:
	keyStackArray["blank"].push(f);
}	
	}

//キー文字列を作成
//blankoffsetは、カラセル挿入によるタイミングの遷移量・冒頭挿入以外は基本的に0
switch (blank_pos){
case	"first"	:var blankoffset=1;break;
case	"end"	:var blankoffset=0;break;
case	"none"	:var blankoffset=0;break;
default	:var blankoffset=0;
}
var footage_frame_duration=(1/footageFramerate);
//	リマップキーを作成
	var remapBody=
'Time Remap\n\tFrame\tseconds\t\n';
	for (n=0;n<keyStackArray["remap"].length;n++)
	{
	if(bufDataArray[keyStackArray["remap"][n]]=="blank")
	{	var seedValue=(blank_pos=="first")? 1 : max_lot+1 ;
	}else{	var seedValue=bufDataArray[keyStackArray["remap"][n]]*1 + blankoffset;
	}
	remapBody+="\t";
	remapBody+=keyStackArray["remap"][n].toString(10);
	remapBody+="\t";
if(	blank_method=="expression2" && 
	bufDataArray[keyStackArray["remap"][n]]=="blank"){
	remapBody+=999999;//エクスプレッション2のカラ
}else{
	remapBody+=(seedValue-0.5)*footage_frame_duration;//通常処理
}
	remapBody+="\t\n";
	}

//	エクスプレッション型
	var expBody=(AE_version<6.0)?
'スライダ\tスライダ制御\tEffect\ Parameter\ #1\t\n\tFrame\t\t\n':
'Effects\tスライダ制御\tスライダ\n\tFrame\t\t\n';

	for (n=0;n<keyStackArray["remap"].length;n++)
	{
	expBody+="\t";
	expBody+=keyStackArray["remap"][n].toString(10);
	expBody+="\t";
	if (bufDataArray[keyStackArray["remap"][n]]=="blank")
	{	expBody+=("0");

	}else{	expBody+=(bufDataArray[keyStackArray["remap"][n]]);
	}
	expBody+="\t\n";
	}

//	ブランクキーを作成
//	エクスプレッション型/ブランクセル無し の場合は不要
switch(blank_method){
case "opacity":
//不透明度
	var blankBody=
'Opacity\n\tFrame\tpercent\t\n';
	var blank_='0';
	var cell_='100';
	break;
case "wipe":
//ワイプ
	var blankBody=(AE_version<6.0)?
'変換終了\tリニアワイプ\tEffect\ Parameter\ \#1\t\n\tFrame\tパーセント\t\n':
'Effects\tリニアワイプ\t変換終了\n\tFrame\tpercent\t\n';
	var blank_='100';
	var cell_='0';
	break;
}
//
	for (n=0;n<keyStackArray["blank"].length;n++)
	{

	blankBody+="\t";
	blankBody+=keyStackArray["blank"][n].toString(10);
	blankBody+="\t";
		if(bufDataArray[keyStackArray["blank"][n]]=="blank")
		{blankBody+=blank_}else{blankBody+=cell_};
	blankBody+="\t\n";
	}

//AE6.5以降のエクスプレッションペースト可能な際のエクスプレッション

if(AE_version>=6.5){
//前方キー参照
	var keepPreviewKeyValue='Expression Data\n';
	keepPreviewKeyValue+='if(numKeys){if(nearestKey(time).time<=time){ix=nearestKey(time).index;}else{';
	keepPreviewKeyValue+='ix=(nearestKey(time).index==1)?1:nearestKey(time).index-1;};key(ix).value;}else{myXps.value}';
	keepPreviewKeyValue+='\n';
	keepPreviewKeyValue+='End of Expression Data\n';
//TimeRemap処理 No.1-T(スライダ参照)
	var trExpression='Time Remap\n';
	trExpression+='\tFrame\tseconds\t\n';
	trExpression+='\t0\t0\t\n\n';
	trExpression+='Expression Data\n';
	trExpression+='(effect("スライダ制御")("スライダ")-1)*thisComp.frameDuration;\n';
	trExpression+='End of Expression Data\n';
//blank処理 No.1-B(スライダ参照)
	var blankExpression1='Effects\tチャンネルシフト #2\tアルファを取り込む #2\n';
	blankExpression1+='\tFrame\t\t\n';
	blankExpression1+='\t\t0\t\n\n';
	blankExpression1+='Expression Data\n';
	blankExpression1+='if(effect("スライダ制御")("スライダ").value){1}else{10};\n';
	blankExpression1+='End of Expression Data\n';

//blank処理 No.2(タイムリマップ直接参照)
	var blankExpression2='Effects\tチャンネルシフト #1\tアルファを取り込む #2\n';
	blankExpression2+='\tFrame\t\t\n';
	blankExpression2+='\t\t0\t\n\n';
	blankExpression2+='Expression Data\n';
	blankExpression2+='if(timeRemap.value>=999999){10}else{1};\n';
	blankExpression2+='End of Expression Data\n';

}

//出力
var Result= 'Adobe After Effects ';
Result += AE_version;
Result += ' Keyframe Data\n';
//Result += ;
Result += '\n\tUnits Per Second\t';
Result += compFramerate.toString();
Result += '\n\tSource Width\t';
Result += sizeX.toString();
Result += '\n\tSource Height\t';
Result += sizeY.toString();
Result += '\n\tSource Pixel Aspect Ratio\t1';
Result += '\n\tComp Pixel Aspect Ratio\t1';
Result += '\n';
if (blank_method !="expression1")
{

	if (blank_method =="opacity")
	{
//		ブランク
		Result += '\n';
		Result += blankBody;
	}
//
//	リマップ
	Result += '\n';
	Result += remapBody;
//AE 6.5以上ならキー保持エクスプレッション貼り付け
	if (AE_version >=6.5){Result +=keepPreviewKeyValue+"\n";}

	if (blank_method =="wipe")
	{
//		ブランク
		Result += '\n';
		Result += blankBody;
	}
//AE 6.5以上でメソッドがexpression2ならばブランク処理を貼り付け
if((blank_method=="expression2")&&(AE_version >=6.5)){Result +=blankExpression2+"\n";}
//
} else {
//エクスプレッション1
	Result += '\n';
//AE 6.5以上ならタイムリマップのエクスプレッションを貼り付け
	if (AE_version >=6.5){Result +=trExpression+"\n";}
//スライダボディ
	Result +=expBody+"\n";
//AE 6.5以上ならキープエクスプレッション貼り付け
	if (AE_version >=6.5){Result +=keepPreviewKeyValue+"\n";}
//AE 6.5以上ならカラセルエクスプレッション貼り付け
	if (AE_version >=6.5){Result +=blankExpression1+"\n";}
}

Result += '\n';
Result += 'End of Keyframe Data';

if(myXps.errorCode){myXps.errorCode=0};return Result;
}

