/*
 *	TVP2XPS(TVPStream)
 *		TVPの書き出すcsvファイルをXPS互換テキストにコンバートする
 *		引き数は、TVP-csvデータのテキストストリーム,
 *
 *	TVPaint Animation が書き出す素材ファイルのファイル名
ver1.0
	exportName.layers/Layer ###/###_layerName_#####.png
ver1.1
	exportName.layers/[###] layrtName/[###][#####]layerName|instanceName.png 
 *
 */

//全角数字を半角にして数字以外の文字を捨てる
//書き戻し用関数　nasライブラリの汎用サポート部に入れたほうが良いかも
nas.clipNum=function(myStr)
{
 return myStr.replace(/[０１２３４５６７８９]/g,
  function(h){
   var n = "０１２３４５６７８９".indexOf(h);
   return (n !== -1)? ("0123456789").charAt(n):h;
  }
 ).replace(/[^0-9]/g,"");
}
//clipNum("!2２３４．．００．９ｑｌｌ");
/*
置き換えパターンは場合によっては下記も
０１２３４５６７８９．，＃－＿｜
0123456789.,#-_|
*/
//前後の空白を払う
function chopString(myString){return myString.replace(/^\s+/,"").replace(/\s+$/,"");};

function TVP2XPS(TVPStream)
{
//データ冒頭のみチェックして明確に違うストリームの場合はエラーを返す
if(! TVPStream.match(/^UTF\-8\,\ TVPaint\,\ \"CSV 1\.\d\"/)){ return false;};
//CSVデータをオブジェクト化する
	myTVP=new Object();
/*
TVP11(CSV 1.0/1.1)のプロパティリスト
*/
	myTVP.encoding="UTF-8";
	myTVP.appName="TVPaint";
	myTVP.csvVersion="CSV 1.1";
	myTVP.ProjectName="";
	myTVP.Width=0;
	myTVP.Height=0;
	myTVP.FrameCount=0;
	myTVP.LayerCount=0;
	myTVP.FrameRate;
	myTVP.PixelAspectRatio=1;
	myTVP.FieldMode="Progressive";

	myTVP.layerProps=new Object();//レイヤプロパティトレーラ
/*
プロパティ:
Layers	レイヤ名　＞トラックラベルに変換
Folder	フルパス　要素配置フォルダ　＞MAP情報　MAP作成時にはグループ作成と同時にMAP書き出し
Density	Float 0-1 不透明度
Blending String BlendingMode
Visible	bool /表示
 */
//	myTVP.xSheetMatrix=new Array();//タイムシート配列トレーラ

//ラインで分割して配列に取り込み
	if(TVPStream.match(/\r/)){TVPStream=TVPStream.replace(/\r\n?/g,("\n"));};
	TVPStream=TVPStream.replace(/\"/g,(""));//全ての\"を払う？
	TVPStream=TVPStream.replace(/\n+/g,("\n"));//繰り返しの空行があれば一つに
	TVPStream=TVPStream.replace(/\n$/,"");//末尾が改行ならそれも捨てる
	
	var CSVRecords=TVPStream.split("\n");//改行で分割
/*	TVP-csvは、
	第１・２・３レコードがドキュメントプロパティ・リストと値リストのセット
以降は第一フィールドが　#\d+　ならばフレームデータ　それ以外はレイヤプロパティなので
それらを順次パースする
04-20 2016
*/
//	ドキュメントのバージョン確認
	var docProps=CSVRecords[0].split(",");
	myTVP.encoding	=chopString(docProps[0]);
	myTVP.appName	=chopString(docProps[1]);
	myTVP.csvVersion=chopString(docProps[2]);
	myTVP.frameOrigin=0;//フレームオリジネーション判定
//
//	ドキュメントプロパティ取得
//	myTVP.SrcData=new Object;
	
	var props=CSVRecords[1].split(",");
	var propValues=CSVRecords[2].split(",");
	for (var pid=1;pid<props.length;pid++){
//プロパティ名から空白を払う
		myTVP[(props[pid]).replace(/\s/g,"")]=chopString(propValues[pid]);
	};
//あらかじめレイヤ数分の配列を作成
	myTVP.layers=new Array(myTVP.LayerCount);
	for (var lyID=0;lyID<myTVP.LayerCount;lyID++){
		myTVP.layers[lyID]=new Array();
		myTVP.layers[lyID].Layers;
		myTVP.layers[lyID].Folder;
		myTVP.layers[lyID].Density;
		myTVP.layers[lyID].Blending;
		myTVP.layers[lyID].Visible;
	}
//第4レコードからレイヤデータを取得
	for (var lid=3;lid<CSVRecords.length;lid++){
			var currentDatas=CSVRecords[lid].split(",");
		if(currentDatas[0].match(/^#([0-9]+)/)){
//レコード冒頭が"#[\d]+"
			var currentFrame=parseInt(RegExp.$1,10);
			for (var lyID=1;lyID<currentDatas.length;lyID++){
				myTVP.layers[lyID-1][currentFrame]=chopString(currentDatas[lyID]);//フレーム番号はスキップ配列にファイル名を登録
			}
		}else{
			var propName=currentDatas[0].replace(/^#/,"");
			for (var lyID=1;lyID<currentDatas.length;lyID++){				
				myTVP.layers[lyID-1][propName]=currentDatas[lyID];//フレーム番号はスキップして
			}
		}
	}
	if(typeof myTVP.layers[0][0]=="undefined") myTVP.frameOrigin=1;
/*
	取得したデータの構造は
	myTVP.layers[idx].Layers	>トラック名
	myTVP.layers[idx].Folder	>フルパス　要素配置フォルダ　＞MAP情報　MAP作成時にはグループ作成と同時にMAP書き出し
	myTVP.layers[idx].Density	>Float 0-1 不透明度
	myTVP.layers[idx].Blending	>String BlendingMode
	myTVP.layers[idx].Visible	>bool /表示

ファイル名(1.0)	出力名.layers/Layer レイヤID/レイヤID_レイヤ名_フレームナンバ.拡張子 (インスタンス名サポート無し)
ファイル名(1.1)	出力名.layers/[レイヤID] レイヤ名/[レイヤID][フレーム番号] インスタンス名又はレイヤ名.拡張子

*/
//取得したデータから番号を生成する
//新規のファイル名・エントリ対照オブジェクトを作る
//	myTVP.layers.fileMap[idx]=new Object();
//	レイヤ毎に処理
//	エントリは[レイヤID,レイヤ名,フレームナンバを含むファイル名],[出現順ID,フレーム番号,インスタンス名]

	myTVP.layers.fileMap=new Array(this.LayerCount);//トレーラー配列
//alert("|"+myTVP.csvVersion+"|");
for (var lidx=0;lidx<myTVP.LayerCount;lidx++){
	myTVP.layers.fileMap[lidx]=new Object();
	var myCount=0;
	for (var fidx=0;fidx<myTVP.FrameCount;fidx++){
		var target=myTVP.layers[lidx][fidx+myTVP.frameOrigin];
switch (myTVP.csvVersion){
	case "CSV 1.0":
		if((typeof target != "undefined")&&(target.split("_").length>2)&&(typeof myTVP.layers.fileMap[lidx][target] == "undefined")){
			myCount++;
			myFrameNo=parseInt(target.split("_").reverse()[0],10);
//			alert("lidx:"+[lidx]+":"+[target]+":"+[myCount,myTVP.layers[lidx].Layers+"-"+myFrameNo]);
			myTVP.layers.fileMap[lidx][target]=[myCount,myFrameNo,""];//フォーマット自体にインスタンス名のサポート無し
		}
		break;
	case "CSV 1.1":
	default:
//		alert(target);
		if((typeof target != "undefined")&&(target.match(/\[([0-9]+)\]\[([0-9]+)\]\s(.+)\.png/))&&(typeof myTVP.layers.fileMap[lidx][target] == "undefined")){
			myCount++;
			myFrameNo=parseInt(RegExp.$2,10);
			instanceName=(RegExp.$3==myTVP.layers[lidx].Layers)?"":RegExp.$3;
			myTVP.layers.fileMap[lidx][target]=[myCount,myFrameNo,instanceName];
		}
}

	}
}
//alert(JSON.stringify(myTVP.layers.fileMap[3]));
//XPS互換ストリームに変換
myTVP.toSrcString = function()
{
	var batchStream ="";
	var shellStream ="";

//	var myLineFeed=nas.GUI.LineFeed;
	var myLineFeed="\n";
	var resultStream="nasTIME-SHEET 0.4";
	resultStream	+=myLineFeed;
	resultStream	+="#TVPaint";
	resultStream	+=myLineFeed;
	resultStream	+="##TIME="+nas.Frm2FCT(parseInt(this.FrameCount,10),3,0);
	resultStream	+=myLineFeed;
	resultStream	+="##TRIN=0+00.,\x22\x22";
	resultStream	+=myLineFeed;
	resultStream	+="##TROUT=0+00.,\x22\x22";
	resultStream	+=myLineFeed;
	resultStream	+="##FRAME_RATE="+this.FrameRate;
	resultStream	+=myLineFeed;
//	サイズ展開
	resultStream	+="[sizeX\t\t";
	for(idx=0;idx<this.LayerCount;idx++){resultStream	+=this.Width+"\t";};
	resultStream	+="]";
	resultStream	+=myLineFeed;
	resultStream	+="[sizeY\t\t";
	for(idx=0;idx<this.LayerCount;idx++){resultStream	+=this.Height+"\t";};
	resultStream	+="]";
	resultStream	+=myLineFeed;
	resultStream	+="[aspect\t\t";
	for(idx=0;idx<this.LayerCount;idx++){resultStream	+=parseInt(this.PixelAspectRatio,10)+"\t";};
	resultStream	+="]";
	resultStream	+=myLineFeed;
//	ラベル配置
	resultStream	+="[CELL\tN\t";
	for(idx=0;idx<this.LayerCount;idx++){
//			resultStream	+=this.layerProps.Layers[this.LayerCount-idx-1]+"\t";
			resultStream	+=this.layers[this.LayerCount-idx-1].Layers+"\t";
	};
	resultStream	+="]";
	resultStream	+=myLineFeed;
	
	for(frm=0;frm<this.FrameCount;frm++)
	{
		resultStream	+="\t";
		//TVPaint-csvはダイアログデータをサポートしないので1フィールドスキップ
		resultStream	+="\t";
		for(idx=0;idx<this.LayerCount;idx++)
		{
			var revTarget=this.LayerCount-idx-1;
			var currentKey=this.layers[revTarget][frm+this.frameOrigin];
			var currentValue=(typeof this.layers.fileMap[revTarget][currentKey] =="undefined")?
			this.layers[revTarget][frm+this.frameOrigin]:
			(this.layers.fileMap[revTarget][currentKey][2])?this.layers.fileMap[revTarget][currentKey][2]:
			this.layers.fileMap[revTarget][currentKey][0];

			resultStream	+= currentValue+"\t";
if((false)&&(typeof currentKey != "undefined")&&(currentKey.match(/.*\.png/))){
/*-------------------------------------------バッチ生成*/
	myGroupName=this.layers[this.LayerCount-idx-1].Layers;
	myFolderName=this.layers[this.LayerCount-idx-1].Folder;
//	alert(currentKey);
batchStream +='ren "'+myFolderName+'\\'+ currentKey +'" "'+myFolderName+'\\'+myGroupName+nas.Zf(this.layers.fileMap[revTarget][currentKey][0],4)+'.png"\n';

shellStream +='mv "'+myFolderName+'/'+ currentKey +'" "'+myFolderName+'/'+myGroupName+nas.Zf(this.layers.fileMap[revTarget][currentKey][0],4)+'.png"\n';
/*------------------------------------------- */
};
		}
		resultStream	+=myLineFeed;
	}
	resultStream	+="[END]";
	resultStream	+=myLineFeed;
	resultStream	+="converted from TVPaint-csv";
/*超暫定版
ファイル名を変更するバッチファイル　最初に書きだしたファイルを決め打ちするので
ファイル移動後に実行した場合の結果は責任が持てない　暫定版なので勘弁ね
*/
	resultStream	+="\nrem rename batch commnds\n\n";
	resultStream	+=batchStream;
	resultStream	+="\n\n#!/bin/sh\n\n";
	resultStream	+=shellStream;

	return resultStream;
}
// alert( myTVP.toSrcString());
return myTVP.toSrcString();
}

/*
	書式　XPS2TVP(myXPS)
	引数はオブジェクトでも、ストリームでも受け付ける。
	コンバートするXPSをTVP-csv互換形式で書き出す。
	文字コードのコンバートは特にしていない
	UTF外で書き出されることは無いはずだが、注意
逆変換は保留　21-04 2016
*/
function XPS2TVP(myXPS){
//引数がソースであっても処理する。XPSでない場合はfalse
	if(myXPS instanceof Xps){var sourceXPS=myXPS;}else{
		if((myXPS instanceof String)&&(myXPS.match(/^nasTIME-SHEET/))){
			var sourceXPS=new Xps();
			if(! sourceXPS.readIN(myXPS)){return false;};
		}else{
			return false;
		}
	}
//XPSフォーマット拡張に従ってタイミング以外のデータが発生するので、種別判定して選択する機能が必要
//プロパティをチェックして必要なタイムラインのIDを抽出する
  var myTargetId=[];
  for (var ix=0;ix<myXPS.layers.length;ix ++){
	if(myXPS.layers[ix].option.match(/(timing|still)/i)){myTargetId.push(ix+1)}
  }

//コンバートする
var myTVP=new Array();
	myTVP.recordCount=26;//TVPはレコード長固定
//第一レコードを作る
	var currentRecord="";
var defaultNames="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var ct=0;ct<myTVP.recordCount;ct++){
	if(ct<myTargetId.length){
		currentRecord +=myXPS.layers[myTargetId[ct]-1].name;
	}else{
		currentRecord +=defaultNames.charAt(ct);
	}
	if(ct<(myTVP.recordCount-1)){currentRecord +="\t";}
}
	myTVP.push(currentRecord);
//空レコードを挿入
	myTVP.push(new Array(26).join("\t"));

//第二レコード以降ボディデータを流し込む(桁揃えで固定長レコードにする)
  for (var myFrame=0;myFrame<myXPS.duration();myFrame++){
	currentRecord="";
	for(var LC=0;LC<=myTVP.recordCount;LC++){
		if(LC<myXPS.layers.length){}
		if(LC<myTargetId.length){
			var currentValue=dataCheck(myXPS.xpsBody[myTargetId[LC]][myFrame],myXPS.layers[myTargetId[LC]-1].name);
			if(currentValue=="blank"){currentValue="0";}
			if(currentValue==null){currentValue="";}
			currentRecord+=currentValue+"\t";
		}else{
			if(LC<(myTVP.recordCount-1)){currentRecord +="\t";}
		//空フィールド
		}
	}
	myTVP.push(currentRecord);
  }

return '"'+myTVP.join("\r")+'"\r\n';
}
/*
現在Tsheetのコンバートに対しては、timingタイムラインに限定する処理が未処理(処理済2013.04.29)
シート上のレコードとして数値以外は認められないようなので、これを変換する処理のみ

おっと、改行が\rのみだったようだ。
まだ1バイトファイルサイズが違う…なんかファイル終端だけに\nが付いてる。
*/
/*
	暫定的にXPSストリーム（ソース）で返しているが、オブジェクトのままのほうが良いかもしれない。一考の余地あり？
	この形式で各フォーマットのコンバータを作って一元化したいが、どうよ？
	逆変換も欲しいね。
*/
//end converter

