/*
 * VsqMixer.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.*;

public class VsqNrpn implements Comparable<VsqNrpn> {
    /**
     * <pre>
     * public property int Clock {
     *   get {
     *        return m_clock;
     *    }
     *    set {
     *        m_clock = value;
     *    }
     *};</pre>
     */
    public int Clock;
    private int m_nrpn;
    private byte m_datamsb;
    private byte m_datalsb;
    private boolean m_datalsb_specified = false;
    private Vector<VsqNrpn> m_list;

    public VsqNrpn( int clock, int nrpn, byte data_msb ) {
        Clock = clock;
        m_nrpn = nrpn;
        m_datamsb = data_msb;
        m_datalsb_specified = false;
        m_list = new Vector<VsqNrpn>();
    }

    public VsqNrpn( int clock, int nrpn, byte data_msb, byte data_lsb ) {
        Clock = clock;
        m_nrpn = nrpn;
        m_datamsb = data_msb;
        m_datalsb = data_lsb;
        m_datalsb_specified = true;
        m_list = new Vector<VsqNrpn>();
    }

    private VsqNrpn() {
    }

    public VsqNrpn[] expand() {
        Vector<VsqNrpn> ret = new Vector<VsqNrpn>();
        if ( m_datalsb_specified ) {
            ret.add( new VsqNrpn( Clock, m_nrpn, m_datamsb, m_datalsb ) );
        } else {
            ret.add( new VsqNrpn( Clock, m_nrpn, m_datamsb ) );
        }
        for ( int i = 0; i < m_list.size(); i++ ) {
            VsqNrpn item = m_list.get( i );
            if ( item.m_datalsb_specified ) {
                ret.add( new VsqNrpn( item.Clock, item.m_nrpn, item.m_datamsb, item.m_datalsb ) );
            } else {
                ret.add( new VsqNrpn( item.Clock, item.m_nrpn, item.m_datamsb ) );
            }
        }
        return ret.toArray( new VsqNrpn[0] );
    }

    public static VsqNrpn[] merge( VsqNrpn[] src1, VsqNrpn[] src2 ) {
        Vector<VsqNrpn> ret = new Vector<VsqNrpn>();
        for ( int i = 0; i < src1.length; i++ ) {
            ret.add( src1[i] );
        }
        for ( int i = 0; i < src2.length; i++ ) {
            ret.add( src2[i] );
        }
        Collections.sort( ret );
        return ret.toArray( new VsqNrpn[0] );
    }

    public static NrpnData[] convert( VsqNrpn[] source ) {
        int nrpn = source[0].getNrpn();
        byte msb = (byte)(nrpn >> 8);
        byte lsb = (byte)(nrpn - (nrpn << 8));
        Vector<NrpnData> ret = new Vector<NrpnData>();
        ret.add( new NrpnData( source[0].Clock, (byte)0x63, msb ) );
        ret.add( new NrpnData( source[0].Clock, (byte)0x62, lsb ) );
        ret.add( new NrpnData( source[0].Clock, (byte)0x06, source[0].getDataMsb() ) );
        if ( source[0].getDataLsbSpecified() ) {
            ret.add( new NrpnData( source[0].Clock, (byte)0x26, source[0].getDataLsb() ) );
        }
        for ( int i = 1; i < source.length; i++ ) {
            int tnrpn = source[i].getNrpn();
            byte tmsb = (byte)(tnrpn >> 8);
            byte tlsb = (byte)(tnrpn - (tnrpn << 8));
            if ( tmsb != msb ) {
                ret.add( new NrpnData( source[i].Clock, (byte)0x63, tmsb ) );
                msb = tmsb;
            }
            ret.add( new NrpnData( source[i].Clock, (byte)0x62, tlsb ) );
            ret.add( new NrpnData( source[i].Clock, (byte)0x06, source[i].getDataMsb() ) );
            if ( source[i].getDataLsbSpecified() ) {
                ret.add( new NrpnData( source[i].Clock, (byte)0x26, source[i].getDataLsb() ) );
            }
        }
        return ret.toArray( new NrpnData[0] );
    }

    public int compareTo( VsqNrpn item ) {
        return Clock - item.Clock;
    }

    public void append( int nrpn, byte data_msb ) {
        m_list.add( new VsqNrpn( Clock, nrpn, data_msb ) );
    }

    public void append( int nrpn, byte data_msb, byte data_lsb ) {
        m_list.add( new VsqNrpn( Clock, nrpn, data_msb, data_lsb ) );
    }

    public int getNrpn() {
        return m_nrpn;
    }

    public byte getDataMsb() {
        return m_datamsb;
    }

    public byte getDataLsb() {
        return m_datalsb;
    }

    private boolean getDataLsbSpecified() {
        return m_datalsb_specified;
    }

}