/*
 * VsqMetaText.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.util.*;
import java.text.*;
import java.awt.*;

/**
 * vsqのメタテキストの中身を処理するためのクラス
 * @author  kbinani
 */
public class VsqMetaText implements Cloneable {
    protected VsqCommon common;
    protected VsqMaster master;
    protected VsqMixer mixer;
    //private List<VsqEvent> m_events;
    private VsqEventList m_events;
    //private List<VsqEvent> m_another_events;
    /// <summary>
    /// PIT。ピッチベンド。default=0
    /// </summary>
    private VsqBPList pitchBendBPList;
    /// <summary>
    /// PBS。ピッチベンドセンシティビティ。dfault=2
    /// </summary>
    private VsqBPList pitchBendSensBPList;
    /// <summary>
    /// DYN。ダイナミクス。default=64
    /// </summary>
    private VsqBPList dynamicsBPList;
    /// <summary>
    /// BRE。ブレシネス。default=0
    /// </summary>
    private VsqBPList epRResidualBPList;
    /// <summary>
    /// BRI。ブライトネス。default=64
    /// </summary>
    private VsqBPList epRESlopeBPList;
    /// <summary>
    /// CLE。クリアネス。default=0
    /// </summary>
    private VsqBPList epRESlopeDepthBPList;
    private VsqBPList reso1FreqBPList;
    private VsqBPList reso2FreqBPList;
    private VsqBPList reso3FreqBPList;
    private VsqBPList reso4FreqBPList;
    private VsqBPList reso1BWBPList;
    private VsqBPList reso2BWBPList;
    private VsqBPList reso3BWBPList;
    private VsqBPList reso4BWBPList;
    private VsqBPList reso1AmpBPList;
    private VsqBPList reso2AmpBPList;
    private VsqBPList reso3AmpBPList;
    private VsqBPList reso4AmpBPList;
    /// <summary>
    /// GEN。ジェンダーファクター。default=64
    /// </summary>
    private VsqBPList genderFactorBPList;
    /// <summary>
    /// POR。ポルタメントタイミング。default=64
    /// </summary>
    private VsqBPList portamentoTimingBPList;
    /// <summary>
    /// OPE。オープニング。default=127
    /// </summary>
    private VsqBPList openingBPList;

    public Object clone() {
        VsqMetaText res = new VsqMetaText();
        if ( common != null ) {
            res.common = (VsqCommon)common.clone();
        }
        if ( master != null ) {
            res.master = (VsqMaster)master.clone();
        }
        if ( mixer != null ) {
            res.mixer = (VsqMixer)mixer.clone();
        }
        if ( m_events != null ) {
            res.m_events = new VsqEventList();//                List<VsqEvent>();

            for ( Iterator itr = m_events.iterator(); itr.hasNext();) {
                VsqEvent item = (VsqEvent)itr.next();
                res.m_events.add( (VsqEvent)item.clone() );
            }
        }
        /*if ( m_another_events != null ) {
        res.m_another_events = new List<VsqEvent>();
        foreach ( VsqEvent item in m_another_events ) {
        res.m_another_events.Add( (VsqEvent)item.clone() );
        }
        }*/
        if ( pitchBendBPList != null ) {
            res.pitchBendBPList = (VsqBPList)pitchBendBPList.clone();
        }
        if ( pitchBendSensBPList != null ) {
            res.pitchBendSensBPList = (VsqBPList)pitchBendSensBPList.clone();
        }
        if ( dynamicsBPList != null ) {
            res.dynamicsBPList = (VsqBPList)dynamicsBPList.clone();
        }
        if ( epRResidualBPList != null ) {
            res.epRResidualBPList = (VsqBPList)epRResidualBPList.clone();
        }
        if ( epRESlopeBPList != null ) {
            res.epRESlopeBPList = (VsqBPList)epRESlopeBPList.clone();
        }
        if ( epRESlopeDepthBPList != null ) {
            res.epRESlopeDepthBPList = (VsqBPList)epRESlopeDepthBPList.clone();
        }
        if ( reso1FreqBPList != null ) {
            res.reso1FreqBPList = (VsqBPList)reso1FreqBPList.clone();
        }
        if ( reso2FreqBPList != null ) {
            res.reso2FreqBPList = (VsqBPList)reso2FreqBPList.clone();
        }
        if ( reso3FreqBPList != null ) {
            res.reso3FreqBPList = (VsqBPList)reso3FreqBPList.clone();
        }
        if ( reso4FreqBPList != null ) {
            res.reso4FreqBPList = (VsqBPList)reso4FreqBPList.clone();
        }
        if ( reso1BWBPList != null ) {
            res.reso1BWBPList = (VsqBPList)reso1BWBPList.clone();
        }
        if ( reso2BWBPList != null ) {
            res.reso2BWBPList = (VsqBPList)reso2BWBPList.clone();
        }
        if ( reso3BWBPList != null ) {
            res.reso3BWBPList = (VsqBPList)reso3BWBPList.clone();
        }
        if ( reso4BWBPList != null ) {
            res.reso4BWBPList = (VsqBPList)reso4BWBPList.clone();
        }
        if ( reso1AmpBPList != null ) {
            res.reso1AmpBPList = (VsqBPList)reso1AmpBPList.clone();
        }
        if ( reso2AmpBPList != null ) {
            res.reso2AmpBPList = (VsqBPList)reso2AmpBPList.clone();
        }
        if ( reso3AmpBPList != null ) {
            res.reso3AmpBPList = (VsqBPList)reso3AmpBPList.clone();
        }
        if ( reso4AmpBPList != null ) {
            res.reso4AmpBPList = (VsqBPList)reso4AmpBPList.clone();
        }
        if ( genderFactorBPList != null ) {
            res.genderFactorBPList = (VsqBPList)genderFactorBPList.clone();
        }
        if ( portamentoTimingBPList != null ) {
            res.portamentoTimingBPList = (VsqBPList)portamentoTimingBPList.clone();
        }
        if ( openingBPList != null ) {
            res.openingBPList = (VsqBPList)openingBPList.clone();
        }
        return res;
    }


//        public List<VsqEvent> Events {
    public VsqEventList getEventList() {
        return m_events;
    }


    /*public List<VsqEvent> AnotherEvents {
    get {
    return m_another_events;
    }
    }*/
    public VsqBPList getVsqBPList( VsqCurveType type ) {
        switch ( type ) {
            case BRE:
                return this.epRResidualBPList;
            case BRI:
                return this.epRESlopeBPList;
            case CLE:
                return this.epRESlopeDepthBPList;
            case DYN:
                return this.dynamicsBPList;
            case GEN:
                return this.genderFactorBPList;
            case OPE:
                return this.openingBPList;
            case PBS:
                return this.pitchBendSensBPList;
            case PIT:
                return this.pitchBendBPList;
            case POR:
                return this.portamentoTimingBPList;
            default:
                return null;
        }
    }

    public void setVsqBPList( VsqCurveType type, VsqBPList value ) {
        switch ( type ) {
            case BRE:
                this.epRResidualBPList = value;
                break;
            case BRI:
                this.epRESlopeBPList = value;
                break;
            case CLE:
                this.epRESlopeDepthBPList = value;
                break;
            case DYN:
                this.dynamicsBPList = value;
                break;
            case GEN:
                this.genderFactorBPList = value;
                break;
            case OPE:
                this.openingBPList = value;
                break;
            case PBS:
                this.pitchBendSensBPList = value;
                break;
            case PIT:
                this.pitchBendBPList = value;
                break;
            case POR:
                this.portamentoTimingBPList = value;
                break;
        }
    }

    /*// <summary>
    /// LyricEvents用に使用できる空きID番号を取得します．next=0の時は次に利用可能なID，next=1は，next=0として得られるIDを使用した後利用可能なID，etc..
    /// </summary>
    /// <returns></returns>
    private int GetNextId_( int next ) {
    int index = -1;
    int count = m_events.Count;
    boolean[] list = new boolean[count];
    for ( int i = 0; i < count; i++ ) {
    list[i] = false;
    }
    for ( int i = 0; i < count; i++ ) {
    if ( 0 <= m_events[i].InternalID && m_events[i].InternalID < count ) {
    list[i] = true;
    }
    }
    int j = -1;
    for ( int i = 0; i < count; i++ ) {
    if ( !list[i] ) {
    j++;
    if ( j == next ) {
    return i;
    }
    }
    }
    return count + next + 1;
    }
    private int GetNextId( int next ) {
    int index = -1;
    List<int> current = new List<int>();
    for ( int i = 0; i < m_events.Count; i++ ) {
    current.Add( m_events[i].InternalID );
    }
    int nfound = 0;
    while ( true ) {
    index++;
    boolean found = false;
    for ( int i = 0; i < current.Count; i++ ) {
    if ( index == current[i] ) {
    found = true;
    break;
    }
    }
    if ( !found ) {
    nfound++;
    if ( nfound == next + 1 ) {
    return index;
    } else {
    current.Add( index );
    }
    }
    }
    }*/
    /*// <summary>
    /// AnotherEvents用に使用できる次の空きID番号を取得します
    /// </summary>
    /// <returns></returns>
    public int GetNextIdForAnotherEvent( int next ) {
    int index = -1;
    List<int> current = new List<int>();
    for ( int i = 0; i < m_another_events.Count; i++ ) {
    current.Add( m_another_events[i].InternalID );
    }
    int nfound = 0;
    while ( true ) {
    index++;
    boolean found = false;
    for ( int i = 0; i < current.Count; i++ ) {
    if ( index == current[i] ) {
    found = true;
    break;
    }
    }
    if ( !found ) {
    nfound++;
    if ( nfound == next + 1 ) {
    return index;
    } else {
    current.Add( index );
    }
    }
    }
    }*/
/// <summary>
/// Editor画面上で上からindex番目のカーブを表すBPListを求めます
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
    /*public VsqBPList GetCurve(
    int index ) {
    switch ( index ) {
    case 1:
    return DYN;
    case 2:
    return BRE;
    case 3:
    return BRI;
    case 4:
    return CLE;
    case 5:
    return OPE;
    case 6:
    return GEN;
    case 7:
    return POR;
    case 8:
    return PIT;
    case 9:
    return PBS;
    default:
    return null;
    }
    
    }*/
    /// <summary>
    /// Editor画面上で上からindex番目のカーブの名前を調べます
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public static String getCurveName( int index ) {
        switch ( index ) {
            case 0:
                return "VEL";
            case 1:
                return "DYN";
            case 2:
                return "BRE";
            case 3:
                return "BRI";
            case 4:
                return "CLE";
            case 5:
                return "OPE";
            case 6:
                return "GEN";
            case 7:
                return "POR";
            case 8:
                return "PIT";
            case 9:
                return "PBS";
            default:
                return "";
        }

    }

    /// <summary>
    /// Singerプロパティに指定されている
    /// </summary>
    public String getSinger() {
        for ( Iterator itr = m_events.iterator(); itr.hasNext();) {
            VsqEvent item = (VsqEvent)itr.next();
            if ( item.ID.type == VsqIDType.Singer ) {
                return item.ID.IconHandle.IDS;
            }
        }
        return "";
    }

    public void setSinger( String value ) {
        for ( Iterator itr = m_events.iterator(); itr.hasNext();) {
            VsqEvent item = (VsqEvent)itr.next();
            if ( item.ID.type == VsqIDType.Singer ) {
                item.ID.IconHandle.IDS = value;
                break;
            }
        }
    }

    /// <summary>
    /// EOSイベントが記録されているクロックを取得します。
    /// </summary>
    /// <returns></returns>
    public int getIndexOfEos() {
        int result;
        if ( m_events.size() > 0 ) {
            int ilast = m_events.size() - 1;
            result = m_events.get( ilast ).Clock;
        } else {
            result = -1;
        }

        return result;
    }

    /**
     * このインスタンスから、IDとHandleのリストを構築します
     *
     *@param id
     *@param handle
     **/
    private void buildIdHandleList( Vector<VsqID> id, Vector<VsqHandle> handle ) {
        id = new Vector<VsqID>();
        handle = new Vector<VsqHandle>();
        int current_id = -1;
        int current_handle = -1;
        Vector<VsqEvent> events = new Vector<VsqEvent>();
        for ( Iterator itr = m_events.iterator(); itr.hasNext();) {
            VsqEvent item = (VsqEvent)itr.next();
            events.add( item );
        }
        Collections.sort( events );
        for ( int i = 0; i < events.size(); i++ ) {
            VsqEvent item = events.get( i );
            VsqID id_item = (VsqID)item.ID.clone();
            current_id++;
            item.ID.value = current_id;
            id_item.value = current_id;
            // IconHandle
            if ( item.ID.IconHandle != null ) {
                current_handle++;
                VsqHandle handle_item = (VsqHandle)item.ID.IconHandle.clone();
                handle_item.Index = current_handle;
                handle.add( handle_item );
                id_item.IconHandle_index = current_handle;
            }

            // LyricHandle
            if ( item.ID.LyricHandle != null ) {
                current_handle++;
                VsqHandle handle_item = (VsqHandle)item.ID.LyricHandle.clone();
                handle_item.Index = current_handle;
                handle.add( handle_item );
                id_item.LyricHandle_index = current_handle;
            }

            // VibratoHandle
            if ( item.ID.VibratoHandle != null ) {
                current_handle++;
                VsqHandle handle_item = (VsqHandle)item.ID.VibratoHandle.clone();
                handle_item.Index = current_handle;
                handle.add( handle_item );
                id_item.VibratoHandle_index = current_handle;
            }

            id.add( id_item );
        }

    }


    /// <summary>
    /// このインスタンスの内容を指定されたファイルに出力します。
    /// </summary>
    /// <param name="sw"></param>
    /// <param name="encode"></param>
    public void print( TextMemoryStream sw, boolean encode, long eos, int start ) {
        //using ( StreamWriter sw = new StreamWriter( fpath ) ) {
        if ( common != null ) {
            common.write( sw );
        }

        if ( master != null ) {
            master.write( sw );
        }

        if ( mixer != null ) {
            mixer.write( sw );
        }

        Vector<VsqID> id = null;
        Vector<VsqHandle> handle = null;
        buildIdHandleList( id, handle );
        writeEventList( sw, eos );
        int i;
        for ( i = 0; i < id.size(); i++ ) {
            id.get( i ).write( sw );
        }

        for ( i = 0; i < handle.size(); i++ ) {
            handle.get( i ).write( sw, encode );
        }

        if ( pitchBendBPList.size() > 0 ) {
            pitchBendBPList.print( sw, start, "[PitchBendBPList]" );
        }

        if ( pitchBendSensBPList.size() > 0 ) {
            pitchBendSensBPList.print( sw, start, "[PitchBendSensBPList]" );
        }

        if ( dynamicsBPList.size() > 0 ) {
            dynamicsBPList.print( sw, start, "[DynamicsBPList]" );
        }

        if ( epRResidualBPList.size() > 0 ) {
            epRResidualBPList.print( sw, start, "[EpRResidualBPList]" );
        }

        if ( epRESlopeBPList.size() > 0 ) {
            epRESlopeBPList.print( sw, start, "[EpRESlopeBPList]" );
        }

        if ( epRESlopeDepthBPList.size() > 0 ) {
            epRESlopeDepthBPList.print( sw, start, "[EpRESlopeDepthBPList]" );
        }

        if ( reso1FreqBPList.size() > 0 ) {
            reso1FreqBPList.print( sw, start, "[Reso1FreqBPList]" );
        }

        if ( reso2FreqBPList.size() > 0 ) {
            reso2FreqBPList.print( sw, start, "[Reso2FreqBPList]" );
        }

        if ( reso3FreqBPList.size() > 0 ) {
            reso3FreqBPList.print( sw, start, "[Reso3FreqBPList]" );
        }

        if ( reso4FreqBPList.size() > 0 ) {
            reso4FreqBPList.print( sw, start, "[Reso4FreqBPList]" );
        }

        if ( reso1BWBPList.size() > 0 ) {
            reso1BWBPList.print( sw, start, "[Reso1BWBPList]" );
        }

        if ( reso2BWBPList.size() > 0 ) {
            reso2BWBPList.print( sw, start, "[Reso2BWBPList]" );
        }

        if ( reso3BWBPList.size() > 0 ) {
            reso3BWBPList.print( sw, start, "[Reso3BWBPList]" );
        }

        if ( reso4BWBPList.size() > 0 ) {
            reso4BWBPList.print( sw, start, "[Reso4BWBPList]" );
        }

        if ( reso1AmpBPList.size() > 0 ) {
            reso1AmpBPList.print( sw, start, "[Reso1AmpBPList]" );
        }

        if ( reso2AmpBPList.size() > 0 ) {
            reso2AmpBPList.print( sw, start, "[Reso2AmpBPList]" );
        }

        if ( reso3AmpBPList.size() > 0 ) {
            reso3AmpBPList.print( sw, start, "[Reso3AmpBPList]" );
        }

        if ( reso4AmpBPList.size() > 0 ) {
            reso4AmpBPList.print( sw, start, "[Reso4AmpBPList]" );
        }

        if ( genderFactorBPList.size() > 0 ) {
            genderFactorBPList.print( sw, start, "[GenderFactorBPList]" );
        }

        if ( portamentoTimingBPList.size() > 0 ) {
            portamentoTimingBPList.print( sw, start, "[PortamentoTimingBPList]" );
        }

        if ( openingBPList.size() > 0 ) {
            openingBPList.print( sw, start, "[OpeningBPList]" );
        }
//}

    }

    private void writeEventList( TextMemoryStream sw, long eos ) {
        sw.writeLine( "[EventList]" );
        Vector<VsqEvent> temp = new Vector<VsqEvent>();
        /*foreach ( VsqEvent item in m_another_events ) {
        temp.Add( item );
        }*/
        for ( Iterator itr = m_events.iterator(); itr.hasNext();) {
            temp.add( (VsqEvent)itr.next() );
        }

        Collections.sort( temp );
        int i = 0;
        DecimalFormat df = new DecimalFormat( "0000" );
        while ( i < temp.size() ) {
            VsqEvent item = temp.get( i );
            if ( !item.ID.equals( VsqID.EOS ) ) {
                String ids = "ID#" + df.format( i );
                int clock = temp.get( i ).Clock;
                while ( i + 1 < temp.size() && clock == temp.get( i + 1 ).Clock ) {
                    i++;
                    ids += ",ID#" + df.format( i );
                }

                sw.writeLine( clock + "=" + ids );
            }

            i++;
        }

        sw.writeLine( eos + "=EOS" );
    }


/// <summary>
/// 何も無いVsqMetaTextを構築する。これは、Master Track用のMetaTextとしてのみ使用されるべき
/// </summary>
    public VsqMetaText() {
    }


    /// <summary>
    /// 最初のトラック以外の一般のメタテキストを構築。(Masterが作られない)
    /// </summary>
    public VsqMetaText( String name, String singer ) {
        this( name, 0, singer, false );
    }


    /// <summary>
    /// 最初のトラックのメタテキストを構築。(Masterが作られる)
    /// </summary>
    /// <param name="pre_measure"></param>
    public VsqMetaText( String name, String singer, int pre_measure ) {
        this( name, pre_measure, singer, true );
    }

    private VsqMetaText( String name, int pre_measure, String singer, boolean is_first_track ) {
        common = new VsqCommon( name, new Color( 179, 181, 123 ), 1, 1 );
        pitchBendBPList = new VsqBPList( 0, -8192, 8192 );
        pitchBendBPList.add( 0, pitchBendBPList.getDefault() );

        pitchBendSensBPList = new VsqBPList( 2, 0, 24 );
        pitchBendSensBPList.add( 0, pitchBendSensBPList.getDefault() );

        dynamicsBPList = new VsqBPList( 64, 0, 127 );
        dynamicsBPList.add( 0, dynamicsBPList.getDefault() );

        epRResidualBPList = new VsqBPList( 0, 0, 127 );
        epRResidualBPList.add( 0, epRResidualBPList.getDefault() );

        epRESlopeBPList = new VsqBPList( 64, 0, 127 );
        epRESlopeBPList.add( 0, epRESlopeBPList.getDefault() );

        epRESlopeDepthBPList = new VsqBPList( 0, 0, 127 );
        epRESlopeDepthBPList.add( 0, epRESlopeDepthBPList.getDefault() );

        reso1FreqBPList = new VsqBPList( 255, 0, 255 );
        reso1FreqBPList.add( 0, reso1FreqBPList.getDefault() );

        reso2FreqBPList = new VsqBPList( 255, 0, 255 );
        reso2FreqBPList.add( 0, reso2FreqBPList.getDefault() );

        reso3FreqBPList = new VsqBPList( 255, 0, 255 );
        reso3FreqBPList.add( 0, reso3FreqBPList.getDefault() );

        reso4FreqBPList = new VsqBPList( 255, 0, 255 );
        reso4FreqBPList.add( 0, reso4FreqBPList.getDefault() );

        reso1BWBPList = new VsqBPList( 255, 0, 255 );
        reso1BWBPList.add( 0, reso1BWBPList.getDefault() );

        reso2BWBPList = new VsqBPList( 255, 0, 255 );
        reso2BWBPList.add( 0, reso2BWBPList.getDefault() );

        reso3BWBPList = new VsqBPList( 255, 0, 255 );
        reso3BWBPList.add( 0, reso3BWBPList.getDefault() );

        reso4BWBPList = new VsqBPList( 255, 0, 255 );
        reso4BWBPList.add( 0, reso4BWBPList.getDefault() );

        reso1AmpBPList = new VsqBPList( 255, 0, 255 );
        reso1AmpBPList.add( 0, reso1AmpBPList.getDefault() );

        reso2AmpBPList = new VsqBPList( 255, 0, 255 );
        reso2AmpBPList.add( 0, reso2AmpBPList.getDefault() );

        reso3AmpBPList = new VsqBPList( 255, 0, 255 );
        reso3AmpBPList.add( 0, reso3AmpBPList.getDefault() );

        reso4AmpBPList = new VsqBPList( 255, 0, 255 );
        reso4AmpBPList.add( 0, reso4AmpBPList.getDefault() );

        genderFactorBPList = new VsqBPList( 64, 0, 127 );
        genderFactorBPList.add( 0, genderFactorBPList.getDefault() );

        portamentoTimingBPList = new VsqBPList( 64, 0, 127 );
        portamentoTimingBPList.add( 0, portamentoTimingBPList.getDefault() );

        openingBPList = new VsqBPList( 127, 0, 127 );
        openingBPList.add( 0, openingBPList.getDefault() );

        if ( is_first_track ) {
            master = new VsqMaster( pre_measure );
        } else {
            master = null;
        }

        m_events = new VsqEventList();
        //m_another_events = new List<VsqEvent>();
        VsqID id = new VsqID( 0 );
        id.type = VsqIDType.Singer;
        id.IconHandle = new IconHandle();
        id.IconHandle.Type = VsqHandleType.Singer;
        id.IconHandle.IconID = "$07010000";
        id.IconHandle.IDS = singer;
        id.IconHandle.Original = 0;
        id.IconHandle.Caption = "";
        id.IconHandle.Length = 1;
        id.IconHandle.Language = 0;
        id.IconHandle.Program = 0;
        m_events.add( new VsqEvent( 0, id ) );
    }

    public VsqMetaText( TextMemoryStream sr ) {
        Vector<KeyValuePair<Integer, Integer>> t_event_list = new Vector<KeyValuePair<Integer, Integer>>();
        //SortedDictionary<int, int> t_event_list = new SortedDictionary<int, int>();
        TreeMap<Integer, VsqID> __id = new TreeMap<Integer, VsqID>();
        TreeMap<Integer, VsqHandle> __handle = new TreeMap<Integer, VsqHandle>();
        pitchBendBPList = new VsqBPList( 0, -8192, 8192 );
        pitchBendSensBPList = new VsqBPList( 2, 0, 24 );
        dynamicsBPList = new VsqBPList( 64, 0, 127 );
        epRResidualBPList = new VsqBPList( 0, 0, 127 );
        epRESlopeBPList = new VsqBPList( 64, 0, 127 );
        epRESlopeDepthBPList = new VsqBPList( 0, 0, 127 );
        reso1FreqBPList = new VsqBPList( 255, 0, 255 );
        reso2FreqBPList = new VsqBPList( 255, 0, 255 );
        reso3FreqBPList = new VsqBPList( 255, 0, 255 );
        reso4FreqBPList = new VsqBPList( 255, 0, 255 );
        reso1BWBPList = new VsqBPList( 255, 0, 255 );
        reso2BWBPList = new VsqBPList( 255, 0, 255 );
        reso3BWBPList = new VsqBPList( 255, 0, 255 );
        reso4BWBPList = new VsqBPList( 255, 0, 255 );
        reso1AmpBPList = new VsqBPList( 255, 0, 255 );
        reso2AmpBPList = new VsqBPList( 255, 0, 255 );
        reso3AmpBPList = new VsqBPList( 255, 0, 255 );
        reso4AmpBPList = new VsqBPList( 255, 0, 255 );
        genderFactorBPList = new VsqBPList( 64, 0, 127 );
        portamentoTimingBPList = new VsqBPList( 64, 0, 127 );
        openingBPList = new VsqBPList( 127, 0, 127 );

        TextResult last_line = new TextResult( "" );
        last_line.set( sr.readLine() );
        while ( true ) {
            if ( last_line.get().length() == 0 ) {
                break;
            }

            if ( last_line.get().equals( "[Common]" ) ) {
                common = new VsqCommon( sr, last_line );
            } else if ( last_line.get().equals( "[Master]" ) ) {
                master = new VsqMaster( sr, last_line );
            } else if ( last_line.get().equals( "[Mixer]" ) ) {
                mixer = new VsqMixer( sr, last_line );
            } else if ( last_line.get().equals( "[EventList]" ) ) {
                last_line.set( sr.readLine() );
                while ( !last_line.get().startsWith( "[" ) ) {
                    String[] spl2 = last_line.get().split( "=" );
                    int clock = Integer.parseInt( spl2[0] );
                    int id_number = -1;
                    if ( spl2[1] != "EOS" ) {
                        String[] ids = spl2[1].split( "," );
                        for ( int i = 0; i < ids.length; i++ ) {
                            String[] spl3 = ids[i].split( "#" );
                            id_number = Integer.parseInt( spl3[1] );
                            t_event_list.add( new KeyValuePair<Integer, Integer>( clock, id_number ) );
                        }
                    } else {
                        t_event_list.add( new KeyValuePair<Integer, Integer>( clock, -1 ) );
                    }

                    if ( sr.peek() < 0 ) {
                        break;
                    } else {
                        last_line.set( sr.readLine() );
                    }

                }
            } else if ( last_line.get().equals( "[PitchBendBPList]" ) ) {
                last_line.set( pitchBendBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[PitchBendSensBPList]" ) ) {
                last_line.set( pitchBendSensBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[DynamicsBPList]" ) ) {
                last_line.set( dynamicsBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[EpRResidualBPList]" ) ) {
                last_line.set( epRResidualBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[EpRESlopeBPList]" ) ) {
                last_line.set( epRESlopeBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[EpRESlopeDepthBPList]" ) ) {
                last_line.set( epRESlopeDepthBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso1FreqBPList]" ) ) {
                last_line.set( reso1FreqBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso2FreqBPList]" ) ) {
                last_line.set( reso2FreqBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso3FreqBPList]" ) ) {
                last_line.set( reso3FreqBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso4FreqBPList]" ) ) {
                last_line.set( reso4FreqBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso1BWBPList]" ) ) {
                last_line.set( reso1BWBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso2BWBPList]" ) ) {
                last_line.set( reso2BWBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso3BWBPList]" ) ) {
                last_line.set( reso3BWBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso4BWBPList]" ) ) {
                last_line.set( reso4BWBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso1AmpBPList]" ) ) {
                last_line.set( reso1AmpBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso2AmpBPList]" ) ) {
                last_line.set( reso2AmpBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso3AmpBPList]" ) ) {
                last_line.set( reso3AmpBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[Reso4AmpBPList]" ) ) {
                last_line.set( reso4AmpBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[GenderFactorBPList]" ) ) {
                last_line.set( genderFactorBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[PortamentoTimingBPList]" ) ) {
                last_line.set( portamentoTimingBPList.readFrom( sr ) );
            } else if ( last_line.get().equals( "[OpeningBPList]" ) ) {
                last_line.set( openingBPList.readFrom( sr ) );
            } else {
                String buffer = last_line.get();
                buffer =
                        buffer.replace( "[", "" );
                buffer =
                        buffer.replace( "]", "" );
                String[] spl = buffer.split( "#" );
                int index = Integer.parseInt( spl[1] );
                if ( last_line.get().startsWith( "[ID#" ) ) {
                    __id.put( index, new VsqID( sr, index, last_line ) );
                } else if ( last_line.get().startsWith( "[h#" ) ) {
                    __handle.put( index, new VsqHandle( sr, index, last_line ) );
                }



            }

            if ( sr.peek() < 0 ) {
                break;
            }

        }

        // まずhandleをidに埋め込み
        for ( int i = 0; i <
                __id.size(); i++ ) {
            if ( __handle.containsKey( __id.get( i ).IconHandle_index ) ) {
                __id.get( i ).IconHandle = __handle.get( __id.get( i ).IconHandle_index ).ConvertToIconHandle();
            }

            if ( __handle.containsKey( __id.get( i ).LyricHandle_index ) ) {
                __id.get( i ).LyricHandle = __handle.get( __id.get( i ).LyricHandle_index ).ConvertToLyricHandle();
            }

            if ( __handle.containsKey( __id.get( i ).VibratoHandle_index ) ) {
                __id.get( i ).VibratoHandle = __handle.get( __id.get( i ).VibratoHandle_index ).ConvertToVibratoHandle();
            }

        }

        // idをeventListに埋め込み
        m_events = new VsqEventList();//            List<VsqEvent>();
        //m_another_events = new List<VsqEvent>();

        for ( int i = 0; i < t_event_list.size(); i++ ) {
            KeyValuePair<Integer, Integer> item = t_event_list.get( i );
            int clock = item.Key;
            int id_number = item.Value;
            if ( __id.containsKey( id_number ) ) {
                //if ( __id[id_number].type == VsqIDType.Anote ) {
                m_events.add( new VsqEvent( clock, (VsqID)__id.get( id_number ).clone() ) );
            //} else {
            //    m_another_events.Add( new VsqEvent( clock, (VsqID)__id[id_number].clone(), GetNextIdForAnotherEvent( 0 ) ) );
            //}
            }

        }
    }

}

