/*
 *	Xpsオブジェクト生成
		2007.04.03 エラーメッセージ分離
		2013.04.02 外部フォーマット解析部分分離
 */
/*
	Xpsオブジェクト初期化手順
		Xpsオブジェクトの新規作成
		コンストラクタ
	myXPS=new Xps([layer count][,frame length]);

Xpsクラスオブジェクトコンストラクタ

引数は、省略可能。
省略時はレイヤ数０，フレーム数０
セルの初期値は全て""
マップの設定はなし(ダミーマップも参照していない)

このオブジェクトはフレーム優先。
フレームレートを変えるとコマうちが変わるのではなく、カットの継続時間が変わる。
アニメーターの振ったコマ打ち優先!(これでいいのかなぁ?)


		XPSオブジェクトの再初期化
	method	[object Xps].init([layer count][,frame length])
自分自身を再初期化する。
すべてのプロパティをリセット
指定されたレイヤ数とフレーム長で空の値のテーブルを作成する。
以前のデータは消去。new_XPSは、内部でこのメソッドを呼ぶ。

		MAPオブジェクトの参照メソッド
	method	[object Xps].getMap([object Map])
このメソッドに引数としてマップオブジェクト[省略不可]を与える。
マップファイルがない場合は、falseを戻す。
現在の使用には、明示的にダミーオブジェクトを与える。
戻り値は取り込み成功時に true 
マップオブジェクトを参照して得られるプロパティは、
レイヤ情報初期値群
タイトル・サブタイトル 初期値

		現在の継続時間を返す
	method	[object Xps].duration()
このメソッドは、プロパティに変更予定
		
		現在のカット尺を返す
	method	[object Xps].time()
このメソッドは、プロパティに変更予定

		カット尺をフレーム数で返す
	method	[object Xps].getTC(フレーム数)
暫定メソッド、消えそう


		テキスト形式データを読み込んでオブジェクトに反映
	method	[object Xps].readIN(テキストデータ)
init()と一体化した方が良いかも

		テキスト形式で出力
	method	[object Xps].toString(セパレータ)
そのうち拡張
と思っていたが、コンバータは別立てにしてXpsオブジェクトの汎用性を高めるが吉

	method	[object Xps].mkAEKey(レイヤID)
モードよっては不要ぽい
同上

メソッド一覧

Xps.newLayers= function(layerCount)://レイヤプロパティトレーラを作成して返す

*/
/*
	XpsStageオブジェクトコンストラクタ
*/
function XpsStage(myParent,myName,myNote)
{
	this.parent =myParent;//Objemct Xps
	this.name   =  myName;//String
	this.note   =  myNote;//String
}
/*
	XpsLayerオブジェクトコンストラクタ
	ラベルを与えて初期化
*/
function XpsLayer(myName,myOpt){
		this.name	=  myName	;
		this.sizeX	=   "640"	;
		this.sizeY	=   "480"	;
		this.aspect	=     "1"	;
		this.lot	="=AUTO="	;
		this.blmtd	=  "wipe"	;
		this.blpos	=   "end"	;
		this.option	=(!myOpt)? "timing":myOpt;
		this.link	=     "."	;
		this.parent	=     "."	;
}
/*
				object Xps コンストラクタ
*/
function Xps(Layers,Length)
{
	if(! Layers) Layers=0;
	if(! Length) Length=0;
	///////////
//Xps標準のプロパティ設定
/*
	すべてのプロパティでXpsを初期化するのは、基準値トレーラーとしての基底オブジェクトのみ
	(ステージ＝null)
	以降のステージは、基底オブジェクトをprototypeとして作成される。
*/
	this.parent	=	null;//親Xps参照用プロパティ　初期値はnull（参照無し）
	this.stage	=	new XpsStage(this,"","");//オブジェクトでないほうが良いかも
	this.mapfile	=	"";//ファイルパスでなく参照オブジェクトに変更所定
	this.opus	=	(myOpus)? myOpus :"--";
	this.title	=	(myTitle)? myTitle:"noTitle";
	this.subtitle	=	(mySubTitle)? mySubTitle:"--";
	this.scene	=	(myScene)? myScene:"";
	this.cut	=	(myCut)? myCut:"";

	this.trin	=	[0,"trin"];
	this.trout	=	[0,"trout"];
	this.rate	=	(!nas)? "24FPS":nas.RATE;
	this.framerate	=	(!nas)? 24:nas.FRATE;
		var Now= new Date();
	this.create_time	=	(!nas)? Now.toString():Now.toNASString();
	this.create_user	=	myName;
	this.update_time	=	"";
	this.update_user	=	myName;
//		レイヤプロパティ設定()　:コレは別オブジェクトにする
	this.layers	=	this.newLayers(Layers);
	this.memo	=	"";

//	XPS配列の作成
	this.xpsBody= this.newBody(Layers+2,Length);
}
//Xps.のメソッドを定義
//レイヤプロパティトレーラを作成して返す
Xps.prototype.newLayers= function(layerCount,camCount){
	if(!camCount){camCount=0};
	var myLayers=new Array();
	var defaultNames="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	var cellCount=layerCount-camCount;
	for (var idx=0;idx<cellCount;idx++){
		myLayers.push(new XpsLayer(defaultNames.charAt(idx),"timing"));
	}
	for (var idx=0;idx<camCount;idx++){
		myLayers.push(new XpsLayer(defaultNames.charAt(idx),"camera"));
	}
	return myLayers;
}
/*
	新規タイムライントレーラを作成
	タイムライントレーラーは、レイヤプロパティトレーラーの数+2
	加えられた2つのタイムラインは、固定のダイアログタイムライン及びフレームコメントタイムラインとして使用される。
	このタムラインは、レコードの開始及び終了マーカーを兼ねるので削除できないので注意
	レイヤ数0のシートのタイムライン数は2である。
*/
Xps.prototype.newBody=function(myLayers,myFrames){
	if(! myLayers) myLayers=this.layers.length+2;//+2
	if(! myFrames) myFrames=this.framerate;
	var myBody=new Array(myLayers);
	for (var lid=0;lid<myBody.length;lid++){
		myBody[lid]=new Array();
		for(var fid=0;fid<myFrames;fid++){myBody[lid][fid]=""}
	}
	return myBody;
}
//再初期化
Xps.prototype.init=function(Layers,Length)
{
	if(! Layers) Layers=0;
	if(! Length) Length=0;
	///////////
//Xps標準のプロパティ設定
	this.mapfile	=	"";
	this.opus	=	myOpus;
	this.title	=	myTitle;
	this.subtitle	=	mySubTitle;
	this.scene	=	myScene;
	this.cut	=	myCut;

	this.trin	=	[0,"trin"];
	this.trout	=	[0,"trout"];

	this.rate	=	(!nas)? "24FPS":nas.RATE;
	this.framerate	=	(!nas)? 24:nas.FRATE;
		var Now= new Date();
	this.create_time	=(!nas)?Now.toString():Now.toNASString();
	this.create_user	=	myName;
	this.update_time	=	"";
	this.update_user	=	myName;
//		レイヤプロパティ設定()
	this.layers=this.newLayers(Layers);
	this.memo	=	"";

//	XPS配列の作成
	this.xpsBody= this.newBody(Layers+2,Length);
}

//	マップオブジェクトを与えて初期化
Xps.prototype.getMap=function(MAP)
{
//マップ無ければ失敗
	if(! MAP) {
			xUI.errorCode=5;return false;
			}

//		レイヤプロパティ設定()
	this.layers.length	=(MAP.mapBody.length-2 >this.layers.length)?
	MAP.mapBody.length-2 : this.layers.length;//大きいほうを採る
//		レイヤプロパティを取得する。マップに無い情報はパスする。
//	マップが小さい場合は元に情報が残る?不足分はデフォルトで埋めるか?
	for (id=0;id<(MAP.mapBody.length-2);id++)
	{
//レイヤのプロパティをMAPオブジェクトのプロパティから読み込む(ダミーだけど)
//	読み込んだジオメトリは、セル(グループ)のジオメトリであって、
//	個々のエントリのジオメトリではない点に注意。
		var name	=MAP.groups[id+1][0];
		var sizeX	=MAP.getgeometry(id+1,"sizeX");
		var sizeY	=MAP.getgeometry(id+1,"sizeY");
		var aspect	=MAP.getgeometry(id+1,"aspect");
		var lot		=MAP.getmaxlot(id+1);
		var blmtd	="wipe";	//りまぴん専用?
		var blpos	="end";	//
		var option	="timing";	//
		var link	=".";	//リンクする親オブジェクト
			//"."区切りでIDナンバでパスを(暫定)
		this["layers"][id]=new Array();

			this["layers"][id]["name"]	=name	;
			this["layers"][id]["sizeX"]	=sizeX	;
			this["layers"][id]["sizeY"]	=sizeY	;
			this["layers"][id]["aspect"]	=aspect	;
			this["layers"][id]["lot"]	=lot	;
			this["layers"][id]["blmtd"]	=blmtd	;
			this["layers"][id]["blpos"]	=blpos	;
			this["layers"][id]["option"]	=option	;
			this["layers"][id]["link"]	=link	;
	}
}
//
/*
	継続時間をフレーム数で返す
	ダイアログタイムラインの要素数で返す
	初期状態でボディの存在しないシートが存在しないように注意
	未記述でも空ボディのタイムラインが存在する。
	エラー関連コードは排除の方向で
*/
//Xps.prototype.duration=function(){if(xUI.errorCode){xUI.errorCode=0};return this.xpsBody[0].length;};
Xps.prototype.duration=function(){return this.xpsBody[0].length;};
//
//	カット尺をフレーム数で返す
//Xps.prototype.time=function(){if(xUI.errorCode){xUI.errorCode=0};return (this.duration()-Math.ceil((this.trin[0]+this.trout[0])/2));};
Xps.prototype.time=function(){return (this.duration()-Math.ceil((this.trin[0]+this.trout[0])/2));};
//
//	フレーム数からTCを返す
//Xps.prototype.getTC=function(mtd){if(xUI.errorCode){xUI.errorCode=0};return nas.Frm2FCT(mtd,3,0,this.framerate);}
Xps.prototype.getTC=function(mtd){return (nas)? nas.Frm2FCT(mtd,3,0,this.framerate):Math.floor(mtd/this.framerate)+"+"+mtd%this.framerate+".";}
//仮メソッドアトでキチンとカケ
//
//	編集関連メソッド

//Xpsにタイムタインを挿入
/*
	Xps.insertTL(id,Timelines)
	Timelines(複数可・配列渡し)
	idの前方に引数のタイムラインを挿入
	idが未指定・範囲外の場合、後方へ挿入
	0番タイムラインの前方へは挿入不能(固定のデフォルトタイムライン)
	現状ではデータを持ったままタイムラインを挿入することはできない。
	必ず空のタイムラインが挿入される。
*/
Xps.prototype.insertTL=function(myId,myTimelines){
	if(!(myTimelines instanceof Array)){myTimelines=[myTimelines]};
	if((! myId )||(myId < 1)||( myId >= this.layers.length)){myId=this.layers.length+1};
	var myBodys =[];
	for (var idx=0;idx<myTimelines.length;idx++){
		//挿入データの検査をする　挿入データが文字列ならそのラベルを持つtimingタイムラインと置き換える
	  if(!(myTimelines[idx] instanceof XpsLayer)){
alert(myTimelines[idx].length)
		if(myTimelines[idx]){
	     myTimelines[idx]=new XpsLayer(myTimelines[idx],"timing");
		}else{
	     myTimelines[idx]=new XpsLayer(nas.Zf(idx+myId,2),"timing");
		}
	  }
	　myBodys[idx]=[];
	  for(var ix=0;ix<this.xpsBody[0].length;ix++){myBodys[idx][ix]=""}
	//挿入データを揃えて挿入
	  this.layers.splice (myId+idx-1,0,myTimelines[idx]);
	  this.xpsBody.splice(myId+idx  ,0,myBodys[idx]     );
	}
}	
/*	Xps.deleteTL([id])
	指定idのタイムラインを削除する。1～
	デフォルトの音声タイムラインとフレームコメントの削除はできない
	IDを単独又は配列渡しで

XpsLayer　と　xpsBody はそのうちタイムラインとして統合すべきかと思う。

*/
Xps.prototype.deleteTL=function(args){
	if (! (args instanceof Array)){args=[args]};
	args.sort().reverse();
	for (var idx=0;idx<args.length;idx++){
	      //操作範囲外の値は無視
		var targetIndex=args[idx];
	   if(isNaN(targetIndex)){continue;}
	   if((targetIndex >0)&&(targetIndex <this.xpsBody.length-1)){
		this.layers.splice(targetIndex-1,1);
		this.xpsBody.splice(targetIndex,1);
	   }
	}

}
/*	Xps.reInitBody(newTimelines:int,newDuration:int)

	Xps本体データのサイズを変更する。
	元あったデータ内容は可能な限り保存
	切り捨て分はなくなる。
	新たに出来たレコードは、ヌルストリングデータで埋める。
*/
Xps.prototype.reInitBody=function(newTimelines,newDuration){
	var oldWidth=this.xpsBody.length;
		if(! newTimelines) newTimelines=oldWidth;
	var oldDuration=this.duration();
		if(! newDuration ) newDuration =oldDuration;
	if(newTimelines<3 || newDuration<=0){return false;};
	var widthUp=(newTimelines > oldWidth)?	true:false;
	var durationUp=(newDuration > oldDuration)?	true:false;

	this.xpsBody.length=newTimelines;//配列長(タイムライン数)の設定

//延長したらカラデータで埋めとく
		if(widthUp){
			for (i=0;i<oldWidth;i++)
			{
				this.xpsBody[i].length=newDuration;
				if(durationUp){
					for(f=oldDuration;f<newDuration;f++){this.xpsBody[i][f]='';};
				};
			};
			for (i=oldWidth;i<newTimelines;i++)
			{
				this.xpsBody[i]=new Array(newDuration);
//if(durationUp)
				for(f=0;f<newDuration;f++){this.xpsBody[i][f]='';};
			};
		}else{
			for (i=0;i<newTimelines;i++)
			{
				this.xpsBody[i].length=newDuration;
				if(durationUp)
				{
					for(f=oldDuration;f<newDuration;f++){this.xpsBody[i][f]='';};
				};
			};
		};
//タイムラインが増えた場合は、再描画前にグループ情報の追加が必要・空データを自動生成してやる必要あり
//現在はラベル名以外は直前タイムラインの複製

	this["layers"].length=(newTimelines-2);//(現在決め打ち)
	if(widthUp){
		for(i=oldWidth-2;i<(newTimelines-2);i++){
		this["layers"][i]=new Array();//これ、今はarrayだけど後でコンストラクタ書くこと
 
		this["layers"][i]["name"]	=("00"+i).slice(-2);
		this["layers"][i]["sizeX"]	=this["layers"][oldWidth-3]["sizeX"]	;
		this["layers"][i]["sizeY"]	=this["layers"][oldWidth-3]["sizeY"]	;
		this["layers"][i]["aspect"]	=this["layers"][oldWidth-3]["aspect"]	;
		this["layers"][i]["lot"]	=this["layers"][oldWidth-3]["lot"]	;
		this["layers"][i]["blmtd"]	=this["layers"][oldWidth-3]["blmtd"]	;
		this["layers"][i]["blpos"]	=this["layers"][oldWidth-3]["blpos"]	;
		this["layers"][i]["option"]	=this["layers"][oldWidth-3]["option"]	;
		this["layers"][i]["link"]	=this["layers"][oldWidth-3]["link"]	;
		this["layers"][i]["parent"]	=this["layers"][oldWidth-3]["parent"]	;

		};
	};
	return true;
};
/*	Xps.getRange(Range:[[startC,startF],[endC,endF]])
	範囲内のデータをストリームで返す	
	xpsのメソッドに移行 2013.02.23
*/
Xps.prototype.getRange	=function(Range)
{
	if (! Range) {Range=[[0,0],[this.xpsBody.length-1,this.xpsBody[0].length-1]]}//指定がなければ全体をストリーム変換
	StartAddress	=Range[0];
	EndAddress	=Range[1];
	var xBUF=new Array();var yBUF=new Array();var zBUF=new Array();
//ループして拾い出す
	for (var r=StartAddress[0];r<=EndAddress[0];r++)
	{
		for (var f=StartAddress[1];f<=EndAddress[1];f++)
			xBUF.push(this.xpsBody[r][f]);
		yBUF.push(xBUF.join(","));xBUF.length=0;
	};
	zBUF=yBUF.join("\n");
// ストリームで返す
	return zBUF;
};
/*	Xps.put(アドレス:[startC,startF],データストリーム)
	アドレスを起点にストリームでデータ置き換え
	xpsのメソッドとして設定してあるので、このメソッドで書き換えを行うと
	undo/redo等は無視されるので、undo/redoを伴わない操作時にのみ使用のこと
	レンジオーバーしたデータは無視される
*/
Xps.prototype.put =function(myAddress,myStream)
{
	if ((! myAddress)||(! myStream)){return false}//指定がなければ操作失敗

//データストリームを配列に展開 
	var srcData=new Array(myStream.toString().split("\n").length);
	for (var n=0;n<srcData.length;n++){
	srcData[n]=myStream.toString().split("\n")[n].split(",");
	}
//ループして置き換え
	for (var c=0;c<srcData.length;c++)
	{
		for (var f=0;f<srcData[0].length;f++)
		{
			if((c+myAddress[0]<this.xpsBody.length)&&(f+myAddress[1]<this.xpsBody[0].length)){
			this.xpsBody[c+myAddress[0]][f+myAddress[1]]=srcData[c][f];
			}
		}
	};
};


//	読み込みメソッド
/*
	ラッパとして残置されるが、内部には他フォーマットの判定部分を置かない。
	インポーターとして使用する場合は、更にこの外側にデータ前処理部分をおくか、
	このメソッドをオーバーライドして使用すること。
	戻り値として、parseXps の戻り値を返すこと。2013.04.06
*/
Xps.prototype.readIN=function(datastream){
	if(datastream instanceof Boolean){return datastream};
	return this.parseXps(datastream);
}
//	読み込みメソッドのXpsパーサを分離
/*
	元の読み込みメソッドは、このパーサのラッパとして残置
	他フォーマットのデータパーサはライブラリに分離される。
	このメソッドはXpsのパース専用になる
	(将来の拡張用として必須)2013.04.06
*/
Xps.prototype.parseXps=function(datastream)
{
//	xUI.errorCode=0;//読み込みメソッドが呼ばれたので最終のエラーコードを捨てる。
//	if(!(datastream instanceof String)){alert (datastream.toString());return datastream;}
//	if(! datastream.toString().length ){
//		xUI.errorCode=1;return false;
//"001:データ長が0です。読み込みに失敗したかもしれません",
//	};
	if(! datastream.match){return false};
//ラインで分割して配列に取り込み
	var SrcData=new Array();
	if(datastream.match(/\r/)){datastream=datastream.replace(/\r\n?/g,("\n"))};
	SrcData=datastream.split("\n");
//		var AEK=true;//AEKey read-formatTestFlag
//データストリーム判別プロパティ
	SrcData.startLine	=0;//データ開始行
//	SrcData.dataClass	="";//データバージョン識別用に流用？
//データ種別判定は、削除　作業開始2013.04.04
//ソースデータのプロパティ
	SrcData.layerHeader	=0;//レイヤヘッダ開始行
	SrcData.layerProps	=0;//レイヤプロパティエントリ数
	SrcData.layerCount	=0;//レイヤ数
	SrcData.layers= new Array();//レイヤ情報トレーラー
	SrcData.layerBodyEnd	=0;//レイヤ情報終了行
	SrcData.frameCount	=0;//読み取りフレーム数
//第一パス
//データ冒頭の空白行を無視して、データ開始行を取得
//識別行の確認
//冒頭ラインが識別コードまたは空行でなかった場合は、さようなら御免ね
//IEのデータの検証もここでやっといたほうが良い?
	for (l=0;l<SrcData.length;l++)
	{
		if(SrcData[l].match(/^\s*$/))
		{
			continue;
		}else{

		if(MSIE){
	var choped=SrcData[l].charCodeAt(SrcData[l].length-1);
	if(choped<=32)
	SrcData[l] = SrcData[l].slice(0,-1);
		}
		//なぜだかナゾなぜに一文字多いのか?

/*
	データ処理中に含まれていた他フォーマットの解析部分は、
	別ライブラリで吸収するのでこのソースからは削除
	TSX AEK 部分は未処理　2013.0405
	どうしましょったら、どーしましょ まだ思案中 シアンは赤の補色です。
*/
if(SrcData[l].match(/^nasTIME-SHEET\ 0\.[1-4]$/))
{
	SrcData.startLine =l;//データ開始行
	break;
}else{
	this.errorMsg[10]=SrcData[l];//message10に当該トークンを格納
	xUI.errorCode=2;return false;
//	"002:どうもすみません。このデータは読めないみたいダ\n"
}
		}
	};
//第一パスおしまい。なんにもデータが無かったらサヨナラ
//"読み取るデータがないのです。";
	if(SrcData.startLine==0 && SrcData.length==l){ xUI.errorCode=3;return false;}
/*
	if(! SrcData.dataClass){
		this.errorMsg[10]=("009:想定外エラー\n"+SrcData.dataClass + "error!");
		xUI.errorCode=9;return false;
	}
*/	
//##変数名とプロパティ名の対照テーブル//
	var varNames=[
"MAPPING_FILE",
"TITLE",
"SUB_TITLE",
"OPUS",
"SCENE",
"CUT",
"TIME",
"TRIN",
"TROUT",
"FRAME_RATE",
"CREATE_USER",
"UPDATE_USER",
"CREATE_TIME",
"UPDATE_TIME"
	];
	var propNames=[
"mapfile",
"title",
"subtitle",
"opus",
"scene",
"cut",
"time",
"trin",
"trout",
"framerate",
"create_user",
"update_user",
"create_time",
"update_time"
	];
	var props =new Array(varNames.length);
for (i=0;i<varNames.length;i++){props[varNames[i]]=propNames[i];};
//	データ走査第二パス
//		時間プロパティ欠落時のために初期値設定
//		SrcData.time="6+0";
		SrcData.trin=[0,"trin"];
		SrcData.trout=[0,"trout"];

	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].match(/^\#\#([A-Z].*)=(.*)$/))
		{
			nAme=RegExp.$1;vAlue=RegExp.$2;
//	時間関連プロパティを先行して評価。
//	読み取ったフレーム数と指定時間の長いほうでシートを初期化する。
switch (nAme)
{
case	"TRIN":			;//トランシットイン
case	"TROUT":		;//トランシットアウト
		var tm=nas.FCT2Frm(vAlue.split(",")[0]);
		if(isNaN(tm)){tm=0};
		var nm=vAlue.split(",")[1];
		if(! nm){nm=props[nAme]};
			  SrcData[props[nAme]]=[tm,nm];
			break	;
case	"TIME":			;//カット尺
		var tm=nas.FCT2Frm(vAlue);
		if(isNaN(tm)){tm=0}
			  SrcData[props[nAme]]=tm;

			break	;
default:				;//時間関連以外
			SrcData[props[nAme]]=vAlue;
//					判定した値をプロパティで控える
}
		}
//			レイヤヘッダまたは終了識別にマッチ
		if(SrcData[line].match(/^\[(([a-zA-Z]+)\t?.*)\]$/))
		{
//シート終わっていたらメモを取り込んで終了
			if(SrcData[line].match(/\[END\]/))
			{
//	シートボディ終了ライン控え
				SrcData.layerBodyEnd=line;
				SrcData["memo"]='';
				for(li=line+1;li<SrcData.length;li++)
				{
					SrcData["memo"]+=SrcData[li];
					if((li+1) < SrcData.length){SrcData["memo"]+="\n"};//最終行以外は改行を追加
				}

					break ;
			}else{
//各レイヤの情報を取得
//	レイヤヘッダの開始行を記録
				if(SrcData.layerHeader==0)
					{SrcData.layerHeader=line};
//	ロットを記録(最大の行を採る)
				var LayerCount =
				SrcData[line].split("\t").length-3;
				SrcData.layerCount=
				(SrcData.layerCount<LayerCount)?
				LayerCount	:	SrcData.layerCount;
//	エントリ数を記録
				SrcData.layerProps++;
			}
		}else{
//	シートデータ本体の行数を加算
	if(! SrcData[line].match(/^\#.*$/))
	{
		SrcData.frameCount++;	//読み取りフレーム数
	}
		}
	}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
//	第二パス終了・読み取った情報でXPSオブジェクトを再初期化(共通)
	SrcData.duration=
	Math.ceil(SrcData.time+(SrcData.trin[0]+SrcData.trout[0])/2);
//		トランシット時間の処理は要再考。現状は切り上げ
	var SheetDuration=(SrcData.duration>(SrcData.frameCount-1))?
	SrcData.duration : (SrcData.frameCount-1)	;//大きいほう

//	///////////////////////
//	if(dbg) dbgPut("count/duration:"+SrcData.layerCount+":"+SheetDuration);

	this.init(SrcData.layerCount,SheetDuration);//再初期化

//	第二パスで読み取ったプロパティをXPSに転記
//					タイム以外はそのまま転記
	for(id=0;id<propNames.length;id++)
	{
		prpName=propNames[id];
		if(SrcData[prpName] && prpName!="time"){this[prpName]=SrcData[prpName];}
	}

//	読み取りデータを調べて得たキーメソッドとブランク位置を転記
for (var lyr=0;lyr<SrcData.layers.length;lyr++)
{
  this.layers[lyr].blmtd	=SrcData.layers[lyr].blmtd;
  this.layers[lyr].blpos	=SrcData.layers[lyr].blpos;
  this.layers[lyr].lot	=SrcData.layers[lyr].lot;
}

	if(SrcData["memo"]) this["memo"]=SrcData["memo"];//memoがあれば転記


// ///// 各エントリのレイヤプロパティとシート本体情報を取得(第三パス)

		var frame_id=0;//読み取りフレーム初期化

	for(line=SrcData.layerHeader;line<SrcData.layerBodyEnd;line++)
	{
//角括弧で開始するデータはレイヤプロパティ
		if(SrcData[line].match(/^\[(([a-zA-Z]+)\t.*)\]$/))
		{
				var layerProps= RegExp.$1.split("\t");
				var layerPropName=RegExp.$2;
					if(layerPropName=="CELL"){layerPropName="name"};
//	これ(CELL)だけシート表記とプロパティ名が一致していないので置換 一致が少ない場合はテーブルが必要になる
				for (c=0;c<SrcData.layerCount;c++)
				{	this["layers"][c][layerPropName]=layerProps[c+2]	}
		}else{
//ほかコメント以外はすべてシートデータ
			if(!SrcData[line].match(/^\#.*$/))
			{
				myLineAry=(SrcData[line].match(/\t/))? SrcData[line].split("\t"):SrcData[line].replace(/[\;\:\,]/g,"\t").split("\t");
				for (col=1;col<=(SrcData.layerCount+2);col++)
				{
//シート本体データの取得
					this.xpsBody[col-1][frame_id]=
					(myLineAry[col]!=undefined)?
					myLineAry[col].replace(/(^\s*|\s*$)/,""):"";
				}
				frame_id++;
			}
		}
	}


// ///// 読み取ったデータを検査する(データ検査は別のメソッドにしろ!??)
/*
//	マップファイルは、現在サポート無し
//		サポート開始時期未定
//この情報は、他の情報以前に判定して、マップオブジェクトの生成が必要。
//マップ未設定状態では、代用マップを作成して使用。
//代用マップは、デフォルトで存在。
<<
	現在は、代用MAPオブジェクトを先行して作成してあるが、
	本来のマップが確定するのはこのタイミングなので、注意!
>>
*/
if(false){
//MAPPING_FILE=(no file)//値は未設定時の予約値?nullで初期化すべきか?
			if(! this.mapfile) this.mapfile='(no file)';

//マップファイルが未設定ならば、代用マップを使用
//この判定はあまりに雑なので後でなんとかすれ
if(false){
	if(this.mapfile=='(no file)')
	{
		MapObj=MAP;	//とりあえず既存のダミーマップを代入しておく。
	}
}
//マップファイルを読み込んでマップオブジェクトを初期化
	//	そのうちね、今はまだない
//日付関連

//制作日付と制作者が無い場合は、空白で初期化?無視したほうが良いかも
//CREATE_USER=''
//CREATE_TIME=''
			if(! this.create_time) this.create_time='';
			if(! this.create_user) this.create_user='';
//最終更新日付と最終更新者が無い場合は、空白で初期化?
//(これは、どのみち保存時に現在のデータで上書き)
//UPDATE_USER=''
//UPDATE_TIME=''
			if(! this.update_time) this.update_time='';
			if(! this.update_user) this.update_user='';
//
//FRAME_RATE=24//
//フレームレート読み取れてなければ、現在の値で初期化(組み込み注意)
			if(! this.framerate)
			{	this.framerate=nas.FRATE;
			}else{
				nas.FRATE=this.framerate;
			}
//トランシット展開しておく
//TRIN=(時間文字列),(トランシット種別)

if(! this.trin){
	this.trin=[0,"trin"]
}else{
	time=nas.FCT2Frm(this.trin[0]);
	if(isNaN(time)){time=0};
	name=(this.trin[1])?this.trin[1]:"trin";
	this.trin=[time,name];
}
//TROUT=(時間文字列),(トランシット種別)
if(! this.trout){
	this.trout=[0,"trout"];
}else{
	time=nas.FCT2Frm(this.trout[0]);
	if(isNaN(time)){time=0};
	name=(this.trout[1])?this.trout[1]:"trout";
	this.trout=[time,name];
}
//TIMEも一応取り込んでおく。
//実際のデータの継続時間とこの情報の「長いほう」を採る
//TIME=(時間文字列)
//			this.time=nas.FCT2Frm(this.time);
//			if(isNaN(this.time)){this.time=0}

//作品データ
//情報が無い場合は、空白で初期化。マップをみるようになったら。
//マップの情報を参照
//最終作業情報(クッキー)を参照
//ユーザ設定によるデフォルトを参照 などから選択


//TITLE=(未設定とかのほうが良いかも)
			if(! this.title) this.title='';
//SUB_TITLE=(未設定とかのほうが良いかも)
			if(! this.subtitle) this.subtitle='';
//OPUS=()
			if(! this.opus) this.opus='';
//SCENE=()
			if(! this.scene) this.scene='';
//CUT=()
			if(! this.cut) this.cut='';

//シーン?・カット番号は最終状態でもデフォルトは空白に。紛らわしいから。

}
if(xUI.errorCode){alert("error :"+xUI.errorMsg[xUI.errorCode]);
//	xUI.errorCode=0;
	};return true;
};

//
/*
 *	書きだしメソッド
 *
 */
Xps.prototype.toString= function()
{
	var Now=new Date();
//セパレータ文字列調整
	var	bold_sep='\n#';
		for(n=this.layers.length+2;n>0;n--) bold_sep+='========';
	var	thin_sep='\n#';
		for(n=this.layers.length+2;n>0;n--) thin_sep+='--------';
//	ヘッダで初期化
	var result='nasTIME-SHEET 0.4';//出力変数初期化
//	##共通プロパティ変数設定
	result+='\n##MAPPING_FILE='	+ this.mapfile	;
	result+='\n##TITLE='	+ this.title	;
	result+='\n##SUB_TITLE='	+ this.subtitle	;
	result+='\n##OPUS='	+ this.opus	;
	result+='\n##SCENE='	+ this.scene	;
	result+='\n##CUT='	+ this.cut	;
	result+='\n##TIME='	+ nas.Frm2FCT(this.time(),3,0)	;
	result+='\n##TRIN='	+nas.Frm2FCT(this.trin[0],3,0)+","+ this.trin[1];
	result+='\n##TROUT='	+nas.Frm2FCT(this.trout[0],3,0)+","+ this.trout[1];
	result+='\n##CREATE_USER='	+ this.create_user	;
	result+='\n##UPDATE_USER='	+ this.update_user	;
	result+='\n##CREATE_TIME='	+ this.create_time	;
	result+='\n##UPDATE_TIME='	+ Now.toNASString()	;
	result+='\n##FRAME_RATE='	+ this.framerate	;
//result+='\n##FOCUS='	+11//
//result+='\n##SPIN='	+S3//
//result+='\n##BLANK_SWITCH='	+File//
	result+='\n#';
	result+=bold_sep;//セパレータ####################################
//	レイヤ別プロパティをストリームに追加
	var Lprops=["sizeX","sizeY","aspect","lot","blmtd","blpos","option","link","name"];
//	var Lprops=["sizeX","sizeY","aspect","lot","blmtd","blpos","option","link","CELL"];
	for (var prop=0;prop<Lprops.length;prop++)
	{
		var propName=Lprops[prop];
		var lineHeader=(propName=="name")? 
		'\n[CELL\tN' : '\n[' + propName + '\t';
		result+=lineHeader;
	for (id=0;id<this.layers.length;id++)
	{
		result+="\t"+this["layers"][id][propName];
	}
	result+='\t]';//
		}
//セパレータ
	result+=bold_sep;//セパレータ####################################
//シートボディ
	for(line=0;line<this.duration();line++)
	{
		result+='\n.';//改行＋ラインヘッダ
		for(column=0;column<(this.layers.length+2);column++)
		{
			address=column+'_'+line;
//			if(! Separator){}else{};

				result+='\t'+this.xpsBody[column][line];
//				result+=Separator+this.xpsBody[column][line];

		}
//	1/4秒おきにサブセパレータ/秒セパレータを出力
		if ((line+1)%Math.round(this.framerate/4)==0)
		{
			if((line+1)%Math.round(this.framerate)==0)
			{
				result+=bold_sep;
			}else{
				result+=thin_sep;
			}
		}
	}
//ボディ終了セパレータ
	result+=bold_sep;//セパレータ####################################
//ENDマーク
	result+='\n[END]\n';
//メモ
	result+=this.memo;

// // // // //返す(とりあえず)
//引数を認識していくつかの形式で返すように拡張予定
//セパレータを空白に変換したものは必要
//変更前(開始時点)のバックアップを返すモード必要/ゼロスクラッチの場合は、カラシートを返す。
	if(xUI.errorCode){xUI.errorCode=0};return result;
}
/* =====================================機能分割 20130221
レイヤストリームを正規化する
内部処理用
レイヤのデータ並びと同じ要素数の有効データで埋まった配列を返す

キー作成に必要な機能だが、汎用性があるので分離してXpsのメソッドに
キー作成はXPSのメソッドとして独立させる
*/
Xps.prototype.getNormarizedStream=function(layer_id){
var	layerDataArray	=this.xpsBody[layer_id+1];
		layerDataArray.label=this.layers[layer_id].name;
var	blank_pos	=this.layers[layer_id].blpos;
var	key_max_lot	=(isNaN(this.layers[layer_id].lot))?
			0 : this.layers[layer_id].lot;

var	bflag=(blank_pos)? false : true ;//ブランク処理フラグ
//

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

//シートのタイムラインからフルフレーム有効データの配列を作る
//全フレーム分のバッファ配列を作る
	var bufDataArray=new Array(layerDataArray.length);
//第一フレーム評価・エントリが無効な場合空フレームを設定
	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(false){if(layer_max_lot==0){
	xUI.errorCode=4;return	;
// "変換すべきデータがありません。\n処理を中断します。";
	}}

if(xUI.errorCode){xUI.errorCode=0};return bufDataArray;
}

// Xpsオブジェクト定義終了

/*
//MacOSでシートテキストを読みやすくする為の空白の追加 このせいでデータ量がやたら増える
この関数不要
function spcFill(string,Span)
{
	var charSpan=0;

	for(n=0;n<string.length;n++){
//エントリーの占有幅仮算定、すごく雑、さらにフォント確認していないのでもっと雑
//無いよりマシ程度だね
if(nas.isAdobe){
	if (isWindows){
if(string.charCodeAt(n)<127){charSpan+=1;}else{charSpan+=2;}
	}else{
if(string.charCodeAt(n)<127){charSpan+=2;}else{charSpan+=3;}
	}
}else{
	charSpan+=1;
}
	};
	if(charSpan>Span){charSpan=Span};
	preSpc="";postSpc="";
for (p=0;p<Math.floor((Span-charSpan)/2);p++){preSpc+="\x20"}
for (p=0;p<Span-Math.floor((Span-charSpan)/2)-charSpan;p++){postSpc+="\x20"}
	return preSpc+string+postSpc;
}
*/
