// This code is generated by blanco Framework.
// <summary>blancoCsvで利用する実行時ユーティリティクラス。</summary>
using System;
using System.IO;
using System.Text;

using blanco.sample.csv.io;

namespace blanco.sample.csv.util
{
    /// <summary>blancoCsvで利用する実行時ユーティリティクラス。</summary>
    /// <remarks>
    /// <newpara>このファイルはblanco Frameworkにより自動生成されています。</newpara>
    /// </remarks>
    public class BlancoCsvRuntimeUtil
    {
        /// <summary>与えられたReaderから 与えられたデリミタを使ってトークンを取り出します。</summary>
        /// <param name="argReader">与えられたリーダ。</param>
        /// <param name="delimiter">デリミタ</param>
        /// <param name="isEndOfLine">行の終端であるのかどうかフラグ。</param>
        /// <returns>取り出されたトークン。もはやリーダが空の場合にはnullを返します。</returns>
        public static string ReadToken(TextReader argReader, char delimiter, bool isEndOfLine)
        {
            if (argReader == null)
            {
                throw new ArgumentException("ReadTokenメソッドのリーダにnullが与えられました。");
            }
            StringBuilder buffer = new StringBuilder();
            for (;;) {
                int iRead = argReader.Read();
                if (iRead < 0) {
                    // 終端に到達。
                    if (isEndOfLine == false) {
                        throw new BlancoCsvIOException("行の終端でないのにも関わらずデリミタが現れずに行が終了してしまいました。");
                    }
                    break;
                }
                if (iRead == delimiter) {
                    if (isEndOfLine) {
                        throw new BlancoCsvIOException("行の終端であるべきにも関わらずデリミタが現れました。");
                    }
                    break;
                } else {
                    buffer.Append((char) iRead);
                }
            }
            return buffer.ToString();
        }

        /// <summary>与えられたReaderから ダブルクオート処理付きで 与えられたデリミタを使ってトークンを取り出します。</summary>
        /// <param name="argReader">与えられたリーダ。</param>
        /// <param name="delimiter">デリミタ。</param>
        /// <returns>取り出されたトークン。もはやリーダが空の場合にはnullを返します。</returns>
        public static string ReadTokenWithQuote(TextReader argReader, char delimiter)
        {
            if (argReader == null)
            {
                throw new ArgumentException("ReadTokenWithQuoteメソッドのリーダにnullが与えられました。");
            }
            StringBuilder buffer = new StringBuilder();
            bool isStringStarted = false;
            bool isStringEnded = false;
            // 前回読み込んで、その後未処理のデータを保持します。保持しない場合には -1 を蓄えます。
            int previousChar = -1;
            for (;;) {
                int iRead = -1;
                if (previousChar < 0)
                {
                    iRead = argReader.Read();
                    if (iRead < 0)
                    {
                        // 終端に到達。
                        break;
                    }
                }
                else
                {
                    iRead = previousChar;
                    previousChar = -1;
                }
                if (isStringStarted == false) {
                    if (iRead != '"') {
                        throw new BlancoCsvIOException("ダブルクオート無しで文字列が開始されました。");
                    }
                    // ダブルクオーテーションは読み飛ばします。
                    isStringStarted = true;
                } else if (isStringEnded) {
                    if (iRead == delimiter) {
                        // 文字列終端に到達しました。
                        break;
                    }
                    throw new BlancoCsvIOException("ダブルクオートによる文字列終了より後に文字列が与えられました。");
                } else {
                    // 通常の文字列エリア
                    if (iRead == '"') {
                        // ダブルクオートが重ねられたものでないかどうかチェックします。
                        previousChar = argReader.Read();
                        if (previousChar == '"') {
                            // エスケープされたダブルクオート
                            // 2つでひとつなので、ひとつは読み捨てます。
                            buffer.Append((char) iRead);
                            previousChar = -1;
                        } else {
                            // ダブルクオートによるエスケープではありませんでした。
                            // これは終端を意味しています。
                            isStringEnded = true;
                        }
                    } else {
                        buffer.Append((char) iRead);
                    }
                }
            }
            if (isStringStarted == false) {
                throw new BlancoCsvIOException("ダブルクオートが必要な文字列であるのにダブルクオートによる開始が現れませんでした。");
            }
            if (isStringEnded == false) {
                throw new BlancoCsvIOException("ダブルクオートが必要な文字列であるのにダブルクオートによる終了が現れませんでした。");
            }
            return buffer.ToString();
        }

        /// <summary>ダブルクオートエスケープ処理付きの文字列を取得します。</summary>
        /// <param name="value">書き出したい文字列。</param>
        /// <returns>ダブルクオートエスケープ処理付きの文字列。</returns>
        public static string GetTokenWithQuote(string value)
        {
            if (value == null)
            {
                throw new ArgumentException("GetTokenWithQuoteメソッドのvalueにnullが与えられました。");
            }
            StringWriter writer = new StringWriter();
            writer.Write("\"");

            StringReader reader = new StringReader(value);
            for (;;) {
                int iRead = reader.Read();
                if (iRead < 0) {
                    // 終端に到達。
                    break;
                }
                if (iRead == '\"') {
                    // ダブルクオートは二重で書き出します。
                    writer.Write("\"\"");
                } else {
                    writer.Write((char) iRead);
                }
            }

            writer.Write("\"");
            writer.Close();
            return writer.ToString();
        }

        /// <summary>文字列をバイト配列に変換します。</summary>
        /// <param name="inputString">変換元の文字列。</param>
        /// <returns>バイト配列に変換後の文字列。</returns>
        public static byte[] GetBytes(string inputString)
        {
            if (inputString == null)
            {
                throw new ArgumentException("GetBytesメソッドにnullが与えられました。");
            }
            // 文字列をバイト配列に変換します。
            byte[] inputBytes = Encoding.Unicode.GetBytes(inputString);
            // エンコーディングを取得します。ここではシフトJISへのエンコーディングを取得しています。
            //TODO: 定義書で指定されているエンコードをする必要があります。
            Encoding targetEncoding = Encoding.GetEncoding(932);
            // 実際にコードを変換。
            return Encoding.Convert(Encoding.Unicode, targetEncoding, inputBytes);
        }
    }
}
