/*
 * VsqHandle.java
 * Copyright (c) 2008 kbinani
 *
 * This file is part of jp.sourceforge.lipsync.vsq.
 *
 * jp.sourceforge.lipsync.vsq is free software; you can redistribute it and/or
 * modify it under the terms of the BSD License.
 *
 * jp.sourceforge.lipsync.vsq 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.
 */
package jp.sourceforge.lipsync.vsq;

import java.io.*;
import java.text.*;

/// <summary>
/// ハンドルを取り扱います。ハンドルにはLyricHandle、VibratoHandleおよびIconHandleがある
/// </summary>
public class VsqHandle {
    public VsqHandleType Type;
    public int Index;
    /*protected String m_icon_id;
    protected String m_ids;
    protected Lyric m_lyric;
    protected int m_original;
    protected String m_caption;
    protected int m_length;
    protected int m_start_depth;
    protected int DepthBPNum;
    protected float[] DepthBPX;
    protected int[] DepthBPY;
    protected int m_start_rate;
    protected int RateBPNum;
    protected float[] RateBPX;
    protected int[] RateBPY;
    protected int m_language;
    protected int m_program;*/
    public String IconID;
    public String IDS;
    public Lyric L0;
    public int Original;
    public String Caption;
    public int Length;
    public int StartDepth;
    public int DepthBPNum;
    public float[] DepthBPX;
    public int[] DepthBPY;
    public int StartRate;
    public int RateBPNum;
    public float[] RateBPX;
    public int[] RateBPY;
    public int Language;
    public int Program;

    public LyricHandle ConvertToLyricHandle() {
        LyricHandle ret = new LyricHandle();
        ret.L0 = (Lyric)L0.clone();
        ret.Type = Type;//m_type;

        ret.Index = Index;// m_index;

        return ret;
    }

    public VibratoHandle ConvertToVibratoHandle() {
        VibratoHandle ret = new VibratoHandle();
        ret.Type = Type;
        ret.Index = Index;
        ret.Caption = Caption;
        ret.DepthBPNum = DepthBPNum;
        ret.DepthBPX = DepthBPX;
        ret.DepthBPY = DepthBPY;
        ;
        ret.IconID = IconID;
        ret.IDS = IDS;
        ret.Length = Length;
        ret.Original = Original;
        ret.RateBPNum = RateBPNum;
        ret.RateBPX = RateBPX;
        ret.RateBPY = RateBPY;
        ret.StartDepth = StartDepth;
        ret.StartRate = StartRate;
        return ret;
    }

    public IconHandle ConvertToIconHandle() {
        IconHandle ret = new IconHandle();
        ret.Type = Type;
        ret.Index = Index;
        ret.Caption = Caption;
        ret.IconID = IconID;
        ret.IDS = IDS;
        ret.Language = Language;
        ret.Length = Length;
        ret.Original = Original;
        ret.Program = Program;
        return ret;
    }


    /*public VsqHandleType Type {
    get {
    return m_type;
    }
    set {
    m_type = value;
    }
    }
    
    
    public int Index {
    get {
    return m_index;
    }
    set {
    m_index = value;
    }
    }*/
    /*// <summary>
    /// このインスタンスの簡易コピーを取得します。
    /// </summary>
    /// <returns></returns>
    public object Clone() {
    VsqHandle result = new VsqHandle();
    result.m_type = m_type;
    result.m_index = m_index;
    result.m_icon_id = m_icon_id;
    result.IDS = this.IDS;
    if ( this.L0 != null ) {
    result.L0 = this.L0.Clone();
    }
    result.Original = this.Original;
    result.Caption = this.Caption;
    result.Length = this.Length;
    result.StartDepth = this.StartDepth;
    result.DepthBPNum = this.DepthBPNum;
    if ( this.DepthBPX != null ) {
    result.DepthBPX = (float[])this.DepthBPX.Clone();
    }
    if ( this.DepthBPY != null ) {
    result.DepthBPY = (int[])this.DepthBPY.Clone();
    }
    result.StartRate = this.StartRate;
    result.RateBPNum = this.RateBPNum;
    if ( this.RateBPX != null ) {
    result.RateBPX = (float[])this.RateBPX.Clone();
    }
    if ( this.RateBPY != null ) {
    result.RateBPY = (int[])this.RateBPY.Clone();
    }
    result.Language = this.Language;
    result.Program = this.Program;
    return result;
    }*/
    public VsqHandle() {
    }

    /// <summary>
    /// インスタンスをストリームに書き込みます。
    /// encode=trueの場合、2バイト文字をエンコードして出力します。
    /// </summary>
    /// <param name="sw">書き込み対象</param>
    /// <param name="encode">2バイト文字をエンコードするか否かを指定するフラグ</param>
    public void write( TextMemoryStream sw, boolean encode ) {
        sw.writeLine( this.toString( encode ) );
    }


    /// <summary>
    /// FileStreamから読み込みながらコンストラクト
    /// </summary>
    /// <param name="sr">読み込み対象</param>
    public VsqHandle( TextMemoryStream sr, int value, TextResult last_line ) {
        this.Index = value;
        String[] spl;
        String[] spl2;

        // default値で梅
        this.Type = VsqHandleType.Vibrato;
        IconID = "";
        IDS = "normal";
        L0 = new Lyric( "" );
        Original = 0;
        Caption = "";
        Length = 0;
        StartDepth = 0;
        DepthBPNum = 0;
        DepthBPX = null;
        DepthBPY = null;
        StartRate = 0;
        RateBPNum = 0;
        RateBPX = null;
        RateBPY = null;
        Language = 0;
        Program = 0;

        String tmpDepthBPX = "";
        String tmpDepthBPY = "";
        String tmpRateBPX = "";
        String tmpRateBPY = "";

        // "["にぶち当たるまで読込む
        last_line.set( sr.readLine() );
        while ( !last_line.get().startsWith( "[" ) ) {
            spl = last_line.get().split( "=" );
            if ( spl[0].equals( "Language" ) ) {
                Language = Integer.parseInt( spl[1] );
            } else if ( spl[0].endsWith( "Program" ) ) {
                Program = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "IconID" ) ) {
                IconID = spl[1];
            } else if ( spl[0].equals( "IDS" ) ) {
                IDS = spl[1];
            } else if ( spl[0].equals( "Original" ) ) {
                Original = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "Caption" ) ) {
                Caption = spl[1];
                for ( int i = 2; i < spl.length; i++ ) {
                    Caption += "=" + spl[i];
                }
            } else if ( spl[0].equals( "Length" ) ) {
                Length = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "StartDepth" ) ) {
                StartDepth = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "DepthBPNum" ) ) {
                DepthBPNum = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "DepthBPX" ) ) {
                tmpDepthBPX = spl[1];
            } else if ( spl[0].equals( "DepthBPY" ) ) {
                tmpDepthBPY = spl[1];
            } else if ( spl[0].equals( "StartRate" ) ) {
                StartRate = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "RateBPNum" ) ) {
                RateBPNum = Integer.parseInt( spl[1] );
            } else if ( spl[0].equals( "RateBPX" ) ) {
                tmpRateBPX = spl[1];
            } else if ( spl[0].equals( "RateBPY" ) ) {
                tmpRateBPY = spl[1];
            } else if ( spl[0].equals( "L0" ) ) {
                Type = VsqHandleType.Lyric;
                L0 = new Lyric( spl[1] );
            }
            if ( sr.peek() < 0 ) {
                break;
            }
            last_line.set( sr.readLine() );
        }
        if ( IDS != "normal" ) {
            Type = VsqHandleType.Singer;
        } else if ( IconID != "" ) {
            Type = VsqHandleType.Vibrato;
        } else {
            Type = VsqHandleType.Lyric;
        }

        // RateBPX, RateBPYの設定
        if ( this.Type == VsqHandleType.Vibrato ) {
            if ( RateBPNum > 0 ) {
                RateBPX = new float[RateBPNum];
                spl2 = tmpRateBPX.split( "," );
                for ( int i = 0; i < RateBPNum; i++ ) {
                    RateBPX[i] = Float.parseFloat( spl2[i] );
                }

                RateBPY = new int[RateBPNum];
                spl2 = tmpRateBPY.split( "," );
                for ( int i = 0; i < RateBPNum; i++ ) {
                    RateBPY[i] = Integer.parseInt( spl2[i] );
                }
            } else {
                RateBPX = null;
                RateBPY = null;
            }

            // DepthBPX, DepthBPYの設定
            if ( DepthBPNum > 0 ) {
                DepthBPX = new float[DepthBPNum];
                spl2 = tmpDepthBPX.split( "," );
                for ( int i = 0; i < DepthBPNum; i++ ) {
                    DepthBPX[i] = Float.parseFloat( spl2[i] );
                }

                DepthBPY = new int[DepthBPNum];
                spl2 = tmpDepthBPY.split( "," );
                for ( int i = 0; i < DepthBPNum; i++ ) {
                    DepthBPY[i] = Integer.parseInt( spl2[i] );
                }
            } else {
                DepthBPX = null;
                DepthBPY = null;
            }
        }

    }

    /// <summary>
    /// ハンドル指定子（例えば"h#0123"という文字列）からハンドル番号を取得します
    /// </summary>
    /// <param name="_String">ハンドル指定子</param>
    /// <returns>ハンドル番号</returns>
    public static int HandleIndexFromString( String _String ) {
        String[] spl = _String.split( "#" );
        return Integer.parseInt( spl[1] );
    }


    /// <summary>
    /// インスタンスをテキストファイルに出力します
    /// </summary>
    /// <param name="sw">出力先</param>
    public void Print( java.io.BufferedWriter sw ) throws IOException {
        String result = this.toString();
        sw.write( result + "\n" );
    }


    /// <summary>
    /// インスタンスをコンソール画面に出力します
    /// </summary>
    private void Print() {
        String result = this.toString();
        System.out.println( result );
    }


    /// <summary>
    /// インスタンスを文字列に変換します
    /// </summary>
    /// <param name="encode">2バイト文字をエンコードするか否かを指定するフラグ</param>
    /// <returns>インスタンスを変換した文字列</returns>
    public String toString( boolean encode ) {
        String result = "";
        result += "[h#" + (new DecimalFormat( "0000" )).format( Index ) + "]";
        switch ( Type ) {
            case Lyric:
                result += "\nL0=" + L0.toString( encode );
                break;
            case Vibrato:
                DecimalFormat df = new DecimalFormat( "0.000000" );
                result += "\nIconID=" + IconID + "\n";
                result += "IDS=" + IDS + "\n";
                result += "Original=" + Original + "\n";
                result += "Caption=" + Caption + "\n";
                result += "Length=" + Length + "\n";
                result += "StartDepth=" + StartDepth + "\n";
                result += "DepthBPNum=" + DepthBPNum + "\n";
                if ( DepthBPNum > 0 ) {
                    result += "DepthBPX=" + df.format( DepthBPX[0] );
                    for ( int i = 1; i < DepthBPNum; i++ ) {
                        result += "," + df.format( DepthBPX[i] );
                    }
                    result += "\n" + "DepthBPY=" + DepthBPY[0];
                    for ( int i = 1; i < DepthBPNum; i++ ) {
                        result += "," + DepthBPY[i];
                    }
                    result += "\n";
                }
                result += "StartRate=" + StartRate + "\n";
                result += "RateBPNum=" + RateBPNum;
                if ( RateBPNum > 0 ) {
                    result += "\n" + "RateBPX=" + df.format( RateBPX[0] );
                    for ( int i = 1; i < RateBPNum; i++ ) {
                        result += "," + df.format( RateBPX[i] );
                    }
                    result += "\n" + "RateBPY=" + RateBPY[0];
                    for ( int i = 1; i < RateBPNum; i++ ) {
                        result += "," + RateBPY[i];
                    }
                }
                break;
            case Singer:
                result += "\n" + "IconID=" + IconID + "\n";
                result += "IDS=" + IDS + "\n";
                result += "Original=" + Original + "\n";
                result += "Caption=" + Caption + "\n";
                result += "Length=" + Length + "\n";
                result += "Language=" + Language + "\n";
                result += "Program=" + Program;
                break;
            default:
                break;
        }
        return result;

    }

}

