/*
 * Paraselene
 * Copyright (c) 2009, 2010  Akira Terasaki
 * このファイルは同梱されているLicense.txtに定めた条件に同意できる場合にのみ
 * 利用可能です。
 */
package paraselene.mockup;

import java.util.*;
import paraselene.tag.*;
import paraselene.tag.table.*;


class TableSource extends TagSource {
	private class TableEnum {
		String	id;
		int		no;
		TableEnum( String id, int no ){
			this.id = id;
			this.no = no;
		}
		public boolean equals( Object o ) {
			if ( !(o instanceof TableEnum) )	return false;
			TableEnum	te = (TableEnum)o;
			return te.id.equals( this.id );
		}
	}
	private Table	table = null;
	private String	table_name = null;
	private String	enum_name = null;

	TableSource( String html ) {
		super( html, "table", false );
	}

	private void build( ArrayList<TableEnum> list ) {
		table = new Table();
		Tag[]	line = getTagArray();
		for ( int i = 0; i < line.length; i++ ) {
			String	name = line[i].getName();
			if ( !"tr".equals( name ) )	continue;
			Line	copy = new Line();
			Tag[]	clm = line[i].getTagArray();
			for ( int j = 0; j < clm.length; j++ ) {
				String	name2 = clm[j].getName();
				Column.Type	type = null;
				if ( "th".equals( name2 ) )	type = Column.Type.HEADER;
				else if ( "td".equals( name2 ) )	type = Column.Type.DATA;
				if ( type == null )	continue;
				Column	copy2 = new Column( type );
				Attribute[]	attr = clm[j].getAllAttribute();
				for ( int k = 0; k < attr.length; k++ ) {
					copy2.setAttribute( attr[k].getReplica() );
				}
				copy.addColumn( copy2 );
			}
			table.addLine( copy );
		}

		try {
			int	xsize = table.getXsize();
			int	ysize = table.getYsize();
			for ( int y = 0; y < ysize; y++ ) {
				for ( int x = 0; x < xsize; x++ ) {
					if ( table.isJoinedColumn( x, y ) )	continue;
					Column	clm = table.getColumn( x, y );
					String	id = clm.getAttributeToString( "id" );
					if ( id == null )	continue;
					id = id.trim();
					if ( id.isEmpty() )	continue;
					if ( id.indexOf( "paraselene" ) >= 0 )	continue;
					if ( JavaDefine.isDefine( id, true ) ) {
						System.err.println( "id " + id + " は使用できない文字が含まれています。" );
						System.exit( 1 );
					}
					TableEnum	te = new TableEnum( id, x );
					if ( list.contains( te ) ) {
						System.err.println( "同一id " + id + " が存在します。" );
						System.exit( 1 );
					}
					list.add( te );
				}
			}
		}
		catch( Table.TableException e ) {
			System.err.println( toString() );
			e.printStackTrace();
			System.exit( 1 );
		}
	}

	private String setName( String name ) {
		table_name = name;
		if ( table_name == null )	return null;
		table_name = PrePage.name2CamelCase( table_name );
		if ( table_name.isEmpty() ) {
			table_name = null;
			return null;
		}
		return table_name;
	}

	String getEnum( boolean one ) {
		String	name = getAttributeToString( "name" );
		if ( setName( name ) == null )	return "";
		ArrayList<TableEnum>	list = new ArrayList<TableEnum>();
		build( list );
		int	cnt = list.size();
		if ( cnt == 0 )	return "";
		enum_name = table_name + "X";
		StringBuilder	buf = PrePage.getCom( name, " テーブル列アクセッサ", this );
		buf = buf.append( " enum " );
		buf = buf.append( enum_name );
		buf = buf.append( "{\n" );
		for ( int i = 0; i < cnt; i++ ) {
			TableEnum	te = list.get( i );
			buf = buf.append( te.id );
			buf = buf.append( "(" );
			buf = buf.append( Integer.toString( te.no ) );
			buf = buf.append( ")" );
			if ( i == cnt - 1 ) {
				buf = buf.append( ";\n" );
			}
			else {
				buf = buf.append( ",\n" );
			}
		}
		buf = buf.append( "private int paraselene$no;\nprivate " );
		buf = buf.append( enum_name );
		buf = buf.append( "(int n){ paraselene$no = n; }\n" );
		buf = buf.append( PrePage.getCom( name, "インデックス", null ) );
		buf = buf.append( "int get(){ return paraselene$no; }\n" );
		buf = buf.append( "}\n" );
		return buf.append( getAccesser( name, one ) ).toString();
	}

	private static final String	URL_TOP = "http://paraselene.sourceforge.jp/api2/paraselene/tag/table/Table.html#";

	private String makeLink( String title ) {
		String	func = title.split( "\\(" )[0];
		StringBuilder	buf = new StringBuilder( "用" );
		buf = buf.append( func );
		buf = buf.append( ".詳しくは <a href='" );
		buf = buf.append( URL_TOP );
		buf = buf.append( title );
		buf = buf.append( "' target='_blank'>" );
		buf = buf.append( func );
		buf = buf.append( "</a> を参照して下さい.<br>このメソッドをラップします" );
		return buf.toString();
	}

	private StringBuilder makeGet1( String name, String ret ) {
		StringBuilder	buf = new StringBuilder( "Table table=(Table)getTag(" );
		buf = buf.append( Make.escape( name ) );
		buf = buf.append( ");\n" );
		buf = buf.append( "if (table==null) return " );
		buf = buf.append( ret );
		buf = buf.append( ";\n" );
		return buf;
	}

	private StringBuilder makeGetAll( String name, String ret ) {
		StringBuilder	buf = new StringBuilder( "Tag[] tag=getAllTag(" );
		buf = buf.append( Make.escape( name ) );
		buf = buf.append( ");\n" );
		buf = buf.append( "if (tag==null) return " );
		buf = buf.append( ret );
		buf = buf.append( ";\n" );
		buf = buf.append( " if (no<0 || no>=tag.length) return " );
		buf = buf.append( ret );
		buf = buf.append( ";\n" );
		buf = buf.append( "Table table=(Table)tag[no];\n" );
		return buf;
	}

	private StringBuilder isJoinedColumn( String name, boolean one ) {
		String	func = "boolean isJoinedColumn4" + table_name + "(";
		StringBuilder	buf = new StringBuilder();
		StringBuilder	com = PrePage.getCom( name, makeLink( "isJoinedColumn(int, int)" ), null );
		if ( one ) {
			buf = buf.append( com );
			buf = buf.append( func );
			buf = buf.append( enum_name );
			buf = buf.append( " x,int y)throws Table.TableException{\n" );
			buf = buf.append( makeGet1( name, "false" ) );
			buf = buf.append( "return table.isJoinedColumn(x.get(),y);\n}\n" );
		}

		buf = buf.append( com );
		buf = buf.append( func );
		buf = buf.append( "int no," );
		buf = buf.append( enum_name );
		buf = buf.append( " x,int y)throws Table.TableException{\n" );
		buf = buf.append( makeGetAll( name, "false" ) );
		buf = buf.append( "return table.isJoinedColumn(x.get(),y);\n}\n" );
		return buf;
	}

	private StringBuilder getColumn( String name, boolean one ) {
		String	func = "Column getColumn4" + table_name + "(";
		StringBuilder	buf = new StringBuilder();
		StringBuilder	com = PrePage.getCom( name, makeLink( "getColumn(int, int)" ), null );
		if ( one ) {
			buf = buf.append( com );
			buf = buf.append( func );
			buf = buf.append( enum_name );
			buf = buf.append( " x,int y)throws Table.TableException{\n" );
			buf = buf.append( makeGet1( name, "null" ) );
			buf = buf.append( "return table.getColumn(x.get(),y);\n}\n" );
		}

		buf = buf.append( com );
		buf = buf.append( func );
		buf = buf.append( "int no," );
		buf = buf.append( enum_name );
		buf = buf.append( " x,int y)throws Table.TableException{\n" );
		buf = buf.append( makeGetAll( name, "null" ) );
		buf = buf.append( "return table.getColumn(x.get(),y);\n}\n" );
		return buf;
	}

	private StringBuilder joinColumn( String name, boolean one ) {
		String	func = "void joinColumn4" + table_name + "(";
		StringBuilder	buf = new StringBuilder();
		StringBuilder	com = PrePage.getCom( name, makeLink( "joinColumn(int, int, int, int)" ), null );
		if ( one ) {
			buf = buf.append( com );
			buf = buf.append( func );
			buf = buf.append( enum_name );
			buf = buf.append( " x,int y,int xsize,int ysize)throws Table.TableException{\n" );
			buf = buf.append( makeGet1( name, "" ) );
			buf = buf.append( "table.joinColumn(x.get(),y,xsize,ysize);\n}\n" );
		}

		buf = buf.append( com );
		buf = buf.append( func );
		buf = buf.append( "int no," );
		buf = buf.append( enum_name );
		buf = buf.append( " x,int y,int xsize,int ysize)throws Table.TableException{\n" );
		buf = buf.append( makeGetAll( name, "" ) );
		buf = buf.append( "table.joinColumn(x.get(),y,xsize,ysize);\n}\n" );
		return buf;
	}

	private StringBuilder getAccesser( String name, boolean one ) {
		StringBuilder	buf = new StringBuilder();
		buf = buf.append( isJoinedColumn( name, one ) );
		buf = buf.append( getColumn( name, one ) );
		buf = buf.append( joinColumn( name, one ) );
		return buf;
	}

	String getOneAccesser( FunctionInfo info, String seek, boolean one ) {
		String	name = getAttributeToString( "name" );
		if ( setName( name ) == null )	return "";
		if ( getFirstInnerHTMLPart( getAssignedPage().getAllTag( seek ) ) == null )	return "";
		StringBuilder	func = new StringBuilder( info.class_name );
		func = func.append( " " );
		func = func.append( info.func_name );
		func = func.append( "4" );
		func = func.append( table_name );
		func = func.append( "(" );
		StringBuilder	buf = new StringBuilder();
		StringBuilder	com = PrePage.getCom( name, new StringBuilder("用").append(info.func_name).toString(), null );
		if ( one ) {
			buf = buf.append( com );
			buf = buf.append( func );
			buf = buf.append( "int y)throws Table.TableException{\n" );
			buf = buf.append( makeGet1( name, "null" ) );
			buf = buf.append( "return (" );
			buf = buf.append( info.class_name );
			buf = buf.append( ")table.getFirstInnerHTMLPart(y,getAllTag(" );
			buf = buf.append( Make.escape( seek ) );
			buf = buf.append( "));\n}\n" );
		}
		buf = buf.append( com );
		buf = buf.append( func );
		buf = buf.append( "int no,int y)throws Table.TableException{\n" );
		buf = buf.append( makeGetAll( name, "null" ) );
		buf = buf.append( "return (" );
		buf = buf.append( info.class_name );
		buf = buf.append( ")table.getFirstInnerHTMLPart(y,getAllTag(" );
		buf = buf.append( Make.escape( seek ) );
		buf = buf.append( "));\n}\n" );
		return buf.toString();
	}
}

