/*
 * VsqBPList.cs
 * Copyright (c) 2008-2009 kbinani
 *
 * This file is part of Boare.Lib.Vsq.
 *
 * Boare.Lib.Vsq is free software; you can redistribute it and/or
 * modify it under the terms of the BSD License.
 *
 * Boare.Lib.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.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Boare.Lib.Vsq {

    /// <summary>
    /// BPListのデータ部分を取り扱うためのクラス。
    /// </summary>
    [Serializable]
    public class VsqBPList : ICloneable {
        private SortedList<int, int> m_list = new SortedList<int, int>();
        public int Default = 0;
        public int Maximum = 127;
        public int Minimum = 0;

        private class KeyClockIterator : Iterator {
            private SortedList<int, int> m_list;
            private int m_pos;

            public KeyClockIterator( SortedList<int, int> list ) {
                m_list = list;
                m_pos = -1;
            }

            public bool hasNext() {
                if ( m_pos + 1 < m_list.Keys.Count ) {
                    return true;
                } else {
                    return false;
                }
            }

            public object next() {
                m_pos++;
                return m_list.Keys[m_pos];
            }

            public void remove() {
                if ( 0 <= m_pos && m_pos < m_list.Keys.Count ) {
                    int key = m_list.Keys[m_pos];
                    m_list.Remove( key );
                }
            }
        }

        public VsqBPList()
            : this( 0, 0, 64 ) {
        }

        /// <summary>
        /// XMLシリアライズ用
        /// </summary>
        public string Data {
            get {
                string ret = "";
                int count = -1;
                foreach ( int key in m_list.Keys ) {
                    count++;
                    ret += (count == 0 ? "" : "," ) + key + "=" + m_list[key];
                }
                return ret;
            }
            set {
                m_list.Clear();
                string[] spl = value.Split( ',' );
                for ( int i = 0; i < spl.Length; i++ ) {
                    string[] spl2 = spl[i].Split( '=' );
                    if ( spl2.Length < 2 ) {
                        continue;
                    }
                    try {
                        m_list.Add( int.Parse( spl2[0] ), int.Parse( spl2[1] ) );
                    } catch ( Exception ex ) {
#if DEBUG
                        Console.WriteLine( "    ex=" + ex );
                        Console.WriteLine( "    i=" + i + "; spl2[0]=" + spl2[0] + "; spl2[1]=" + spl2[1] );
#endif
                    }
                }
            }
        }

        /// <summary>
        /// このVsqBPListの同一コピーを作成します
        /// </summary>
        /// <returns></returns>
        public object Clone() {
            VsqBPList res = new VsqBPList( Default, Minimum, Maximum );
            foreach ( int key in m_list.Keys ) {
                res.m_list.Add( key, m_list[key] );
            }
            return res;
        }

        /// <summary>
        /// コンストラクタ。デフォルト値はココで指定する。
        /// </summary>
        /// <param name="default_value"></param>
        public VsqBPList( int default_value, int minimum, int maximum ) {
            Default = default_value;
            Maximum = maximum;
            Minimum = minimum;
        }

        /// <summary>
        /// このリストに設定された最大値を取得します。
        /// </summary>
        public int getMaximum() {
            return Maximum;
        }

        /// <summary>
        /// このリストに設定された最小値を取得します
        /// </summary>
        public int getMinimum() {
            return Minimum;
        }

        public Iterator keyClockIterator() {
            return new KeyClockIterator( m_list );
        }

        public void remove( int clock ) {
            if ( m_list.ContainsKey( clock ) ) {
                m_list.Remove( clock );
            }
        }

        public bool isContainsKey( int clock ) {
            return m_list.ContainsKey( clock );
        }

        public int getCount() {
            return m_list.Count;
        }

        public int[] getKeys() {
            List<int> t = new List<int>();
            foreach( int key in m_list.Keys ){
                t.Add( key );
            }
            return t.ToArray();
        }

        public void clear() {
            m_list.Clear();
        }

        /// <summary>
        /// 新しいデータ点を追加します。
        /// </summary>
        /// <param name="clock"></param>
        /// <param name="value"></param>
        public void add( int clock, int value ) {
            lock ( m_list ) {
                if ( m_list.ContainsKey( clock ) ) {
                    m_list[clock] = value;
                } else {
                    m_list.Add( clock, value );
                }
            }
        }

        public int getElement( int index ) {
            return m_list[m_list.Keys[index]];
        }

        public int getKeyClock( int index ) {
            return m_list.Keys[index];
        }

        public int getValue( int clock, ref int index ) {
            if ( m_list.Count == 0 ) {
                return Default;
            } else {
                if ( index < 0 ) {
                    index = 0;
                }
                for ( int i = index ; i < m_list.Keys.Count; i++ ) {
                    int keyclock = m_list.Keys[i];
                    if ( clock < keyclock ) {
                        if ( i > 0 ) {
                            index = i;
                            return m_list[m_list.Keys[i - 1]];
                        } else {
                            index = i;
                            return Default;
                        }
                    }
                }
                index = m_list.Keys.Count - 1;
                return m_list[m_list.Keys[m_list.Keys.Count - 1]];
            }
        }

        public int getValue( int clock ) {
            if ( m_list.Count == 0 ) {
                return Default;
            } else {
                for ( int i = 0; i < m_list.Keys.Count; i++ ) {
                    int keyclock = m_list.Keys[i];
                    if ( clock < keyclock ) {
                        if ( i > 0 ) {
                            return m_list[m_list.Keys[i - 1]];
                        } else {
                            return Default;
                        }
                    }
                }
                return m_list[m_list.Keys[m_list.Keys.Count - 1]];
            }
        }

        public int OLD_getElement( int clock ) {
            if ( m_list.Count == 0 ) {
                return Default;
            } else {
                if ( m_list.ContainsKey( clock ) ) {
                    return m_list[clock];
                } else {
                    int index = 0;
                    int prev = 0;
                    foreach ( int key in m_list.Keys ) {
                        if ( clock < key ) {
                            index = prev;
                            break;
                        }
                        prev = key;
                    }
                    if ( m_list.ContainsKey( index ) ) {
                        return m_list[index];
                    } else {
                        return Default;
                    }
                }
            }
        }

        /// <summary>
        /// このBPListのデフォルト値を取得します
        /// </summary>
        public int getDefault() {
            return Default;
        }

        /// <summary>
        /// このBPListの内容をテキストファイルに書き出します
        /// </summary>
        /// <param name="writer"></param>
        public void print( StreamWriter writer ) {
            bool first = true;
            foreach ( int key in m_list.Keys ) {
                int val = m_list[key];
                if ( first ) {
                    writer.WriteLine( key + "=" + val );
                    first = false;
                } else {
                    writer.WriteLine( key + "=" + val );
                }
            }
        }

        /// <summary>
        /// このBPListの内容をテキストファイルに書き出します
        /// </summary>
        /// <param name="writer"></param>
        public void print( TextMemoryStream writer, int start, string header ) {
            bool first = true;
            foreach ( int key in m_list.Keys ) {
                if ( start <= key ) {
                    if ( first ) {
                        writer.writeLine( header );
                        first = false;
                    }
                    int val = m_list[key];
                    writer.writeLine( key + "=" + val );
                }
            }
        }

        /// <summary>
        /// テキストファイルからデータ点を読込み、現在のリストに追加します
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public string appendFromText( TextMemoryStream reader ) {
            string last_line = reader.readLine();
            while ( !last_line.StartsWith( "[" ) ) {
                string[] spl = last_line.Split( new char[] { '=' } );
                int i1 = int.Parse( spl[0] );
                int i2 = int.Parse( spl[1] );
                m_list.Add( i1, i2 );
                if ( reader.peek() < 0 ) {
                    break;
                } else {
                    last_line = reader.readLine();
                }
            }
            return last_line;
        }
    }

}
