/**********************************************************************
* Copyright (C) 2007 Kyoto University
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-
* 1301  USA
***********************************************************************/
/*
 * This file is the component controller file for Dependency Parser including layout.
 */
//* $Id: dependency-parse.js 2525 2009-03-20 08:55:37Z morimoto $
//* $Date:: 2009-03-20 17:55:37 +0900#$

var DependencyParse = Class.create();
var LanguageMenu = Class.create();
var ResultArea = Class.create();
var ResultParsingContainer = Class.create();

Object.extend( ResultArea, {
	DEP_NONE       : 0,
	DEP_DEPENDENCY : 1,
	DEP_PARALELL   : 2,
	DEP_APPOSITION : 3,

	LD_NONE        : 0,
	LD_UP          : 1,
	LD_DOWN        : 2,
	LD_CROSS       : 3,

	LINE_V         : '&#9474;',//* '│'
	LINE_H         : '&#9472;',//* '─'
	LINE_CROSS     : '&#9532;',//* '┼'
	LINE_CORNER_U  : '&#9492;',//* '└'
	LINE_CORNER_D  : '&#9484;',//* '┌'
	LINE_UP        : '&#9524;',//* '┴'
	LINE_DOWN      : '&#9516;',//* '┬'
	LINE_ARROW_R   : '&#8594;',//* '→'
	LINE_BV        : '&#9475;',//* '┃'
	LINE_BH        : '&#9473;',//* '━'
	LINE_BCORNER   : '&#9491;',//* '┓'
	LINE_NONE      : '&nbsp;&nbsp;',

	countByte : function (str) {
		var byte = 0;
		for (j=0; j < str.length; j++) {
			str.charCodeAt(j) < 0x100 ? byte++ : byte += 2;
		}
		return byte;
	},

	getDependencyFromLabel: function( label ) {
		if ( label == 'DEPENDENCY' ) {
			return ResultArea.DEP_DEPENDENCY;
		} else if ( label == 'PARALELL' ) {
			return ResultArea.DEP_PARALELL;
		} else if ( label == 'APPOSITION' ) {
			return ResultArea.DEP_APPOSITION;
		} else {
			return ResultArea.DEP_NONE;
		}
	}
} );

Object.extend( ResultArea, {
} );

//* new した後にAjax.Requestにより入手したデータをloadTranslationDataで処理する必要がある
DependencyParse.prototype = {
	initialize: function(wordAreaId,languageId,resultAreaId){
		this.wordAreaId = wordAreaId;
		this.languageMenu = new LanguageMenu(languageId);
		this.resultArea = new ResultArea(resultAreaId);
	},

	changeLanguages: function(languages){
		this.languageMenu.setMenuLanguages(languages);
		this.languageMenu.draw();
	},

	resetLanguages: function(){
		this.languageMenu.resetSelectedLanguage();
		this.languageMenu.resetMenuLanguage();
		this.languageMenu.draw();
	},

	isEmptyWordArea: function(){
		return $(this.wordAreaId).value == "";
	},

	getSelectedLanguage: function(){
		return this.languageMenu.getSelectedLanguage();
	},

	getLanguageMenu: function(){
		return this.languageMenu;
	},

	getResultArea: function(){
		return this.resultArea;
	},

	getWordArea: function(){
		return $(this.wordAreaId);
	}
};

LanguageMenu.prototype = {
	initialize: function(id){
		this.id = id;
		this.element = $(this.id);
		this.selectedLanguage = null;
		this.menuLanguages = new Array();
	},

	setSelectedLanguage: function(language){
		this.selectedLanguage = language;
	},

	getSelectedLanguage: function(){
		return this.selectedLanguage;
	},

	getElement: function(){
		return this.element;
	},

	setMenuLanguages: function(languages){
		this.menuLanguages = languages;
	},

	resetSelectedLanguage: function(){
		this.selectedLanguage = null;
	},

	resetMenuLanguage: function(){
		this.menuLanguages = new Array();
	},

	draw: function(){
		this.element.innerHTML = '';
		if (this.menuLanguages.size() == 0) {
			var opt = document.createElement('option');
			opt.innerHTML = '&nbsp;';
			this.element.appendChild(opt);
		}
		else {
			var hasPreviousSelectedLanguage = false;
			for (var n = 0; n < this.menuLanguages.size(); n++) {
				var opt = document.createElement('option');
				if (this.menuLanguages[n] == this.selectedLanguage) {
					opt.selected = "true";
					hasPreviousSelectedLanguage = true;
				}
				opt.value = this.menuLanguages[n];
				opt.innerHTML = Language.getNameByTag( this.menuLanguages[n] );
				this.element.appendChild(opt);
			}
			if (!hasPreviousSelectedLanguage) {
				this.element.firstChild.selected = "true";
				this.selectedLanguage = this.element.firstChild.value;
			}
		}
	}
};

ResultArea.prototype = {

	initialize: function(id){
		this.id = id;
		this.element = $(this.id);
	},

	draw: function(response,resourceSelection){
		var resultObj = eval("("+response+")");
		this.element.innerHTML = '';
		var checker = new StatusProcessor(resultObj);
		var elem = this.element;
		checker.warning = function(){
			if (this.isLimitationWarning()) alert(this.message);
			else {
				var oDiv = document.createElement( 'div' );
				Element.addClassName( oDiv, 'error-message' );
				oDiv.appendChild( document.createTextNode( 'Warning: ' + this.message ) );
				elem.appendChild( oDiv );
			}
			return true;
		}
		checker.error = function(){
			if (this.isLimitationError()) {
				alert(this.message);
				return false;
			} else {
				var oDiv = document.createElement( 'div' );
				Element.addClassName( oDiv, 'error-message' );
				oDiv.appendChild( document.createTextNode( 'Error: ' + this.message ) );
				elem.appendChild( oDiv );
			}
			return true;
		}
		if(!checker.check()) return;

		resultObj = resultObj['contents']['contents'];
		var oDiv = document.createElement( 'div' );
		Element.addClassName( oDiv, 'how-to-see' );

		// eip kawauchi mod start 20100108
		// 表記間違いを修正
//		oDiv.innerHTML = 'PA: Paralell<br />AP: Apposition';
		oDiv.innerHTML = 'PA: Parallel<br />AP: Apposition';
		// eip kawauchi mod end 20100108

		elem.appendChild( oDiv );
		for(var i=0;i<resultObj.length; i++){
			var container = new ResultParsingContainer(resultObj[i]);
			this.element.appendChild(container.getElement(resourceSelection));
		}
	}
};

ResultParsingContainer.prototype = {
	initialize: function(resultObj,number){
		this.resultObj = resultObj;
		this.number = number;
	},

	getElement: function(resourceSelection){
		var res = document.createElement('dl');

		var checker = new StatusProcessor(this.resultObj.result);
		var number = this.number;
		checker.error = function(){
			var divElement = document.createElement('dd');
			divElement.className = "error-message";
			divElement.appendChild(document.createTextNode("Error: "+this.response.message));
			res.appendChild(divElement);
			return true;
		};
		checker.warning = function(){
			var divElement = document.createElement('dd');
			divElement.className = "warning-message";
			divElement.appendChild(document.createTextNode("Warning: "+this.response.message));
			res.appendChild(divElement);
			return this.ok();
		};
		checker.ok = function(){
			var contents = this.response.contents;
			//* sort by chunkId
			contents.sort( function( a, b ) {
				return parseInt( a.chunkId ) - parseInt( b.chunkId );
			} );

			var oDt = document.createElement( 'dt' );
			oDt.appendChild( document.createTextNode( contents.map( function( obj, index ) {
				return obj.morphemes.map( function( m, idx ) { return m.word; } ).join( '' );
			} ).join( '' ) ) );
			res.appendChild( oDt );

			var aryStructure = new Array(); //* Structure for showing figure of results by each chunkIds
			                                //* lineNum: number of lines that is shown at left of chunk
											//* depended: array of the structure of chunkIds and dependency.
											//*           These chunkIds depend on THIS chunkId
											//*   chunkId: chunkId
											//*   dependency: kinds of dependency
											//* end: data of that This chunkId depends on
											//*   chunkId: chunkId
											//*   dependency: kinds of dependency
			var hashDiff = new Hash(); //* Hash of distance of two chunkIds
			                           //* key: distance of two chunkIds. headChunkId - chunkId
									   //* val: array of chunkId
			contents.each( function( obj, index ) {
				var chunkId = parseInt( obj.chunkId );
				var headChunkId = parseInt( obj.dependency.headChunkId );
				if ( headChunkId < 0 ) {
					aryStructure[ chunkId ] = { 'lineNum': -1, 'depended': new Array(), 'end': -1 };
					return;
				}
				var reverse = false;
				var start, end;
				if ( headChunkId > chunkId ) {
					start = chunkId; end = headChunkId;
				} else {
					reverse = true;
					start = headChunkId; end = chunkId;
				}
				for ( var i = start; i < end; i++ ) {
					if ( typeof( aryStructure[i] ) == 'undefined' ) {
						aryStructure[i] = { 'lineNum': -1, 'depended': new Array(), 'end': -1 };
					}
					aryStructure[i].lineNum++;
				}
				aryStructure[ chunkId ].end = {
					'chunkId': headChunkId,
					'dependency': ResultArea.getDependencyFromLabel( obj.dependency.label )
				};
				if ( reverse ) {
					aryStructure[ headChunkId ].depended.push( {
						'chunkId': chunkId,
						'dependency': ResultArea.getDependencyFromLabel( obj.dependency.label )
					} );
				}
				var diff = end - start;
				if ( typeof( hashDiff.get( diff ) ) == 'undefined' ) {
					hashDiff.set( diff, new Array() );
				}
				hashDiff.get( diff ).push( chunkId );
			} );
			var aryLineData = new Array(); //* array of lineData for each chunk
			                               //* lineData: array of line
										   //*   line: kinds of line
			for ( var i = aryStructure.size() - 1; i > 0; i-- ) {
				var lineData = new Array();
				for ( var j = aryStructure.size(); j > 0; j-- ) {
					lineData.push( false );
				}
				aryLineData.push( lineData );
			}
			var maxLine = aryLineData.size();
			hashDiff.keys().sort( function( a, b ) { return parseInt( a ) - parseInt( b ); } )
			.each( function( diff, index ) {
				var aryChunkId = hashDiff.get( diff );
				aryChunkId.each( function( chunkId, idx ) {
					var headChunkId = aryStructure[ chunkId ].end.chunkId;
					var reverse = false;
					var start, end;
					if ( headChunkId > chunkId ) {
						start = chunkId; end = headChunkId;
					} else {
						start = headChunkId; end = chunkId;
						reverse = true;
					}
					for ( var i = 0; i < maxLine; i++ ) {
						var bEmpty = true;
						for ( var j = start; j < end; j++ ) {
							if ( aryLineData[i][j] ) {
								bEmpty = false;
								break;
							}
						}
						if ( bEmpty ) {
							for ( var j = start; j < end; j++ ) {
								aryLineData[i][j] = true;
							}
							aryStructure[ chunkId ].lineNum = i;
							break;
						}
					}
				} );
			} );
			var maxLineNumber = aryStructure.max( function( s, index ) { return s.lineNum; } );

			var aryLineData = new Array();
			for ( var i = maxLineNumber; i >= 0; i-- ) {
				aryLineData.push( { 'count': 0, 'dir': 0 } );
			}

			var oDd = document.createElement( 'dd' );
			contents.each( function( obj, index ) {
				var chunkId = parseInt( obj.chunkId );
				var headChunkId = parseInt( obj.dependency.headChunkId );

				var oTable = document.createElement( 'table' );
				var oTbody = document.createElement( 'tbody' );
				var oTr1, oTr2, oTd;

				oTr1 = document.createElement( 'tr' );
				oTr2 = document.createElement( 'tr' );

				aryStructure[ chunkId ].depended.each( function( d, idx ) {
					if ( d.chunkId < chunkId ) return;
					var max = d.chunkId - chunkId + 1;
					aryLineData[ aryStructure[ d.chunkId ].lineNum ] = {
						'max'  : max,
						'count': max,
						'dir'  : -1
					};
				} );
				var bCorner = false;
				for ( var i = maxLineNumber; i >= 0; i-- ) {
					oTd = document.createElement( 'td' );
					Element.addClassName( oTd, 'line' );
					if ( aryLineData[i].count > 0 ) {
						if ( aryLineData[i].dir > 0 && --aryLineData[i].count <= 0 ) {
							if ( bCorner ) {
								oTd.innerHTML = ResultArea.LINE_UP;
							} else {
								oTd.innerHTML = ResultArea.LINE_CORNER_U;
								bCorner = true;
							};
						} else if ( aryLineData[i].dir < 0 && aryLineData[i].count == aryLineData[i].max ) {
							if ( bCorner ) {
								oTd.innerHTML = ResultArea.LINE_DOWN;
							} else {
								oTd.innerHTML = ResultArea.LINE_CORNER_D;
								bCorner = true;
							};
						} else if ( bCorner ) {
							oTd.innerHTML = ResultArea.LINE_CROSS;
						} else {
							oTd.innerHTML = ResultArea.LINE_V;
						};
					} else if ( bCorner ) {
						oTd.innerHTML = ResultArea.LINE_H;
					} else {
						oTd.innerHTML = ResultArea.LINE_NONE;
					}
					oTr1.appendChild( oTd );
				}
				oTd = document.createElement( 'td' );
				Element.addClassName( oTd, 'line' );
				oTd.innerHTML = ( bCorner ? ResultArea.LINE_ARROW_R : ResultArea.LINE_NONE );
				oTr1.appendChild( oTd );

				if ( aryStructure[ chunkId ].end.chunkId > chunkId ) {
					var max = aryStructure[ chunkId ].end.chunkId - chunkId;
					aryLineData[ aryStructure[ chunkId ].lineNum ] = {
						'max'  : max,
						'count': max,
						'dir'  : 1
					};
				}
				var bCorner = false;
				for ( var i = maxLineNumber; i >= 0; i-- ) {
					oTd = document.createElement( 'td' );
					Element.addClassName( oTd, 'line' );
					if ( aryLineData[i].count > 0 ) {
						if ( aryLineData[i].dir < 0 && --aryLineData[i].count <= 0 ) {
							if ( bCorner ) {
								oTd.innerHTML = ResultArea.LINE_UP;
							} else {
								oTd.innerHTML = ResultArea.LINE_CORNER_U;
								bCorner = true;
							};
						} else if ( aryLineData[i].dir > 0 && aryLineData[i].count == aryLineData[i].max ) {
							if ( bCorner ) {
								oTd.innerHTML = ResultArea.LINE_DOWN;
							} else {
								var dependency = aryStructure[ chunkId ].end.dependency;
								if ( dependency == ResultArea.DEP_PARALELL ) {
									oTd.innerHTML = 'PA';
								} else if ( dependency == ResultArea.DEP_APPOSITION ) {
									oTd.innerHTML = 'AP';
								} else {
									oTd.innerHTML = ResultArea.LINE_CORNER_D;
								}
								bCorner = true;
							};
						} else if ( bCorner ) {
							oTd.innerHTML = ResultArea.LINE_CROSS;
						} else {
							oTd.innerHTML = ResultArea.LINE_V;
						};
					} else if ( bCorner ) {
						oTd.innerHTML = ResultArea.LINE_H;
					} else {
						oTd.innerHTML = ResultArea.LINE_NONE;
					}
					oTr2.appendChild( oTd );
				}
				oTd = document.createElement( 'td' );
				Element.addClassName( oTd, 'line' );
				oTd.innerHTML = ( bCorner ? ResultArea.LINE_H : ResultArea.LINE_NONE );
				oTr2.appendChild( oTd );

				obj.morphemes.each( function( m, idx ) {
					oTd = document.createElement( 'td' );
					Element.addClassName( oTd, 'word' );
					oTd.appendChild( document.createTextNode( m.word ) );
					oTr1.appendChild( oTd );

					oTd = document.createElement( 'td' );
					Element.addClassName( oTd, 'information' );
					oTd.appendChild( document.createTextNode( '[' + m.partOfSpeech + '] ' + m.lemma ) );
					oTr2.appendChild( oTd );
				} );

				oTbody.appendChild( oTr1 );
				oTbody.appendChild( oTr2 );
				oTable.appendChild( oTbody );
				oDd.appendChild( oTable );

				oTable = document.createElement( 'table' );
				oTbody = document.createElement( 'tbody' );
				oTr = document.createElement( 'tr' );

				for ( var i = maxLineNumber; i >= 0; i-- ) {
					oTd = document.createElement( 'td' );
					Element.addClassName( oTd, 'line' );
					if ( aryLineData[i].count > 0 ) {
						oTd.innerHTML = ResultArea.LINE_V;
					} else {
						oTd.innerHTML = ResultArea.LINE_NONE;
					}
					oTr.appendChild( oTd );
				}

				oTbody.appendChild( oTr );
				oTable.appendChild( oTbody );
				oDd.appendChild( oTable );
			} );

			oDd.removeChild( oDd.lastChild );

			res.appendChild( oDd );
			return true;
		};

		if(!checker.check()) return;

		var resourceName = document.createElement('div');
		Element.addClassName( resourceName, 'resource-name' );
		var atag = document.createElement('a');
		atag.appendChild(document.createTextNode(resourceSelection.getResourceNameFromId(this.resultObj.id)));
		atag.setAttribute('href',resourceSelection.getUrlFromId(this.resultObj.id));
		resourceName.appendChild(atag);
		res.appendChild(resourceName);

		return res;
	}
};

DependencyParse.Event = {
	changeLanguage: function(event,resourceSearch){
		var language = resourceSearch.getLanguageMenu().getElement().value;
		resourceSearch.getLanguageMenu().setSelectedLanguage(language);
	}
}
