/* This file is part of AHD ID3 Tag Editor (AITE)
   A program can create and edit ID3 Tag for mp3 files

   Copyright © Ala I.Hadid 2012

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program 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.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AHD.ID3Tag
{
    public class SynchronisedLyricsFrame : ID3v2Frame
    {
        public SynchronisedLyricsFrame()
            : base("SYLT", 0, 0, null)
        { }
        public SynchronisedLyricsFrame(int size, ushort flags, byte[] data)
            : base("SYLT", size, flags, data)
        { }
        public override string Name
        {
            get { return ""; }
        }
        string language = "";
        string contentDescriptor = "";
        string contentType = "";
        TimeStampFormat timeStamp = TimeStampFormat.AbsoluteMilliseconds;
        List<SynchronisedLyricsItem> items = new List<SynchronisedLyricsItem>();
        Encoding encoding = ID3v2EncodingWrapper.ISO_8859_1;
        void DetectEncoding(string val)
        {
            if (encoding.CodePage == ID3v2EncodingWrapper.ISO_8859_1.CodePage)
                encoding = ID3v2EncodingWrapper.GetBestEncoding(val);
        }
        public virtual Encoding Encoding
        { get { return encoding; } set { encoding = value; } }
        public string Language
        {
            get
            {
                return Consts.GetLanguage(language.ToUpper());
            }
            set
            {
                language = Consts.GetLanguageID(value).ToUpper();
            }
        }
        public string ContentType
        {
            get
            {
                return contentType;
            }
            set
            {
                contentType = value;
            }
        }
        public string Description
        { get { return contentDescriptor; } set { contentDescriptor = value; DetectEncoding(value); } }
        public TimeStampFormat TimeStampFormat
        { get { return timeStamp; } set { timeStamp = value; } }
        public List<SynchronisedLyricsItem> Items
        { get { return items; } }
        int GetItemsSize()
        {
            int size = 0;
            foreach (SynchronisedLyricsItem item in items)
            {
                size += encoding.GetByteCount(item.Text + "\0") + 4;
            }
            return size;
        }
        byte GetType(string type)
        {
            for (byte i = 0; i < Consts.SynchronisedLyricsContentTypes.Length; i++)
            {
                if (Consts.SynchronisedLyricsContentTypes[i] == type)
                {
                    return i;
                }
            }
            return 0;
        }

        public override void Load()
        {
            encoding = ID3v2EncodingWrapper.FromByte(Data[0]);
            int index = 1;
            string code = ID3v2EncodingWrapper.ISO_8859_1.GetString(Data, 1, Data.Length - 1);
            language = code.Substring(0, 3);
            index += 3;
            timeStamp = (TimeStampFormat)Data[index];
            if (timeStamp == 0)
                timeStamp = ID3Tag.TimeStampFormat.AbsoluteMilliseconds;
            index += 1;
            contentType = Consts.SynchronisedLyricsContentTypes[Data[index]];
            index += 1;

            code = encoding.GetString(Data, index, Data.Length - index);
            string[] Ltext = code.Split(new char[] { '\0' });
            contentDescriptor = Ltext[0];
            index += encoding.GetByteCount(contentDescriptor + "\0");
            //items
            int TerminationBytesCount = ID3v2EncodingWrapper.GetTerminationBytesCount(encoding);
            items.Clear();
            for (int i = index; i < Data.Length - index; i++)
            {
                string text = "";
                if (TerminationBytesCount == 1)
                {
                    while (encoding.GetString(new byte[] { Data[i] }) != "\0")
                    {
                        text += encoding.GetString(new byte[] { Data[i] });
                        i++;
                    }
                }
                else if (TerminationBytesCount == 2)
                {
                    while (encoding.GetString(new byte[] { Data[i], Data[i + 1] }) != "\0")
                    {
                        text += encoding.GetString(new byte[] { Data[i], Data[i + 1] });
                        i += 2;
                    }
                }
                i += TerminationBytesCount;
                int time = (Data[i] << 24) | (Data[i + 1] << 16) | (Data[i + 2] << 8) | Data[i + 3];
                i += 3;
                items.Add(new SynchronisedLyricsItem(time, text));
            }
        }
        public override int GetSize()
        {
            return 6 + encoding.GetByteCount(contentDescriptor + "\0") + GetItemsSize();
        }
        public override void Save()
        {
            List<byte> data = new List<byte>();
            //encoding, detect for the items
            foreach (SynchronisedLyricsItem item in items)
            {
                DetectEncoding(item.Text);
            }
            data.Add(ID3v2EncodingWrapper.ToByte(encoding));

            //language
            data.AddRange(ID3v2EncodingWrapper.ISO_8859_1.GetBytes(language.ToUpper()));
            //timeStamp
            data.Add((byte)timeStamp);
            //contentType
            data.Add(GetType(contentType));
            //contentDescriptor
            data.AddRange(encoding.GetBytes(contentDescriptor + "\0"));
            //items
            foreach (SynchronisedLyricsItem item in items)
            {
                data.AddRange(encoding.GetBytes(item.Text + "\0"));
                //size
                data.Add((byte)((item.Time & 0xFF000000) >> 24));
                data.Add((byte)((item.Time & 0x00FF0000) >> 16));
                data.Add((byte)((item.Time & 0x0000FF00) >> 08));
                data.Add((byte)((item.Time & 0x000000FF) >> 00));
            }
            //save
            int size = GetSize();
            this.Data = data.ToArray();
        }

        public override string ToString()
        {
            return contentDescriptor + " [" + Language + "]";
        }
    }
}
