/*
 * blanco Framework
 * Copyright (C) 2004-2006 IGA Tosiki
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.fixedlength.expand;

import java.io.File;

import blanco.fixedlength.resourcebundle.BlancoFixedLengthRuntimeUtilDotNetResourceBundle;
import blanco.fixedlength.valueobject.BlancoFixedLengthStructureDotNet;
import blanco.ig.expander.ClassExpander;
import blanco.ig.expander.IgType;
import blanco.ig.expander.IgValue;
import blanco.ig.expander.Scope;
import blanco.ig.expander.Type;
import blanco.ig.expander.Value;
import blanco.ig.expander.method.MethodExpander;

public class BlancoFixedLengthExpandRuntimeUtilDotNet {
    final BlancoFixedLengthRuntimeUtilDotNetResourceBundle bundle = new BlancoFixedLengthRuntimeUtilDotNetResourceBundle();

    public void expand(final BlancoFixedLengthStructureDotNet processStructure,
            final File directoryTarget) {

        final String className = bundle.getClassName();
        final String classNameblancoFixedLengthIOException = processStructure
                .getRuntimePackage()
                + ".io.BlancoFixedLengthIOException";
        final ClassExpander classExpander = new ClassExpander(new Type(
                processStructure.getRuntimePackage()
                        + bundle.getPackagePrefix(), className)) {
            protected void expandClassStruct() {
                addImport(new IgType("System.ArgumentException"));
                addImport(new IgType("System.Text.Encoding"));

                addFileComment(bundle.getFilecomment());
                getJavaDoc().addLine(bundle.getClasscomment01());
                getJavaDoc().addLine(bundle.getClasscomment02());

                addMethod(new MethodExpander(bundle.getReadtokenName()) {
                    protected boolean isStatic() {
                        return true;
                    }

                    // メソッドのシグニチャ指定
                    public void setupSignature() {
                        getJavaDoc().addLine(bundle.getReadtokenJavadoc());
                        addArgument(new Value(new Type(bundle
                                .getReadtokenArg01Type()), bundle
                                .getReadtokenArg01Name()));
                        getJavaDoc().addParameter(
                                bundle.getReadtokenArg01Name(),
                                bundle.getReadtokenArg01Javadoc());

                        addArgument(new Value(new Type(bundle
                                .getReadtokenArg02Type()), bundle
                                .getReadtokenArg02Name()));
                        getJavaDoc().addParameter(
                                bundle.getReadtokenArg02Name(),
                                bundle.getReadtokenArg02Javadoc());

                        setReturnType(new Type(bundle.getReadtokenReturnType()));
                        getJavaDoc().addReturn(
                                bundle.getReadtokenReturnJavadoc());

                        addException(new Type(
                                classNameblancoFixedLengthIOException));
                        getJavaDoc()
                                .addException(
                                        new Type(
                                                classNameblancoFixedLengthIOException),
                                        "項目数が足りないなど与えられた文字列に関する例外が発生した場合。");
                        addException(new Type(bundle.getReadtokenThrows01Type()));
                        getJavaDoc().addException(
                                new Type(bundle.getReadtokenThrows01Type()),
                                bundle.getReadtokenThrows01Javadoc());
                    }

                    // メソッドの実装
                    public void implement() {
                        getData().addLine(bundle.getReadtokenLine01());
                        getData().addLine(bundle.getReadtokenLine02());
                        getData().addLine(bundle.getReadtokenLine03());
                        getData().addLine(bundle.getReadtokenLine04());
                        getData().addLine(bundle.getReadtokenLine05());
                        getData().addLine(bundle.getReadtokenLine06());
                        getData().addLine(bundle.getReadtokenLine07());
                        getData().addLine(bundle.getReadtokenLine08());
                        getData().addLine(bundle.getReadtokenLine09());
                        getData().addLine(bundle.getReadtokenLine10());
                        getData().addLine(bundle.getReadtokenLine11());
                        getData().addLine(bundle.getReadtokenLine12());
                        getData().addLine(bundle.getReadtokenLine13());
                        getData().addLine(bundle.getReadtokenLine14());
                        getData().addLine(bundle.getReadtokenLine15());
                        getData().addLine(bundle.getReadtokenLine16());
                        getData().addLine(bundle.getReadtokenLine17());
                        getData().addLine(bundle.getReadtokenLine18());
                        getData().addLine(bundle.getReadtokenLine19());
                        getData().addLine(bundle.getReadtokenLine20());
                        getData().addLine(bundle.getReadtokenLine21());
                        getData().addLine(bundle.getReadtokenLine22());
                        getData().addLine(bundle.getReadtokenLine23());
                        getData().addLine(bundle.getReadtokenLine24());
                        getData().addLine(bundle.getReadtokenLine25());
                        getData().addLine(bundle.getReadtokenLine26());
                        getData().addLine(bundle.getReadtokenLine27());
                        getData().addLine(bundle.getReadtokenLine28());
                        getData().addLine(bundle.getReadtokenLine29());
                        getData().addLine(bundle.getReadtokenLine30());
                        getData().addLine(bundle.getReadtokenLine31());
                    }
                });

                addMethod(new MethodExpander("PadRight") {
                    protected boolean isStatic() {
                        return true;
                    }

                    public void setupSignature() {
                        getJavaDoc().addLine("与えられた文字列を指定の長さまで右側をパディングします。");

                        getJavaDoc().addParameter("argSource", "入力文字列。");
                        addArgument(new Value(new Type("string"), "argSource"));

                        getJavaDoc()
                                .addParameter("argLength", "目標とするトータルバイト長。");
                        addArgument(new Value(new Type("int"), "argLength"));

                        getJavaDoc().addParameter("argPadChar",
                                "埋める際に利用するパディング文字。");
                        addArgument(new Value(new Type("char"), "argPadChar"));

                        getJavaDoc().addReturn("目標となるバイト長に加工された後の文字列。");
                        setReturnType(new Type("string"));
                    }

                    public void implement() {
                        getData().addLine("if (argSource == null) {");
                        getData()
                                .addLine(
                                        "throw new ArgumentException(\"PadRightの入力文字列に nullが与えられました。\");");
                        getData().addLine("}");
                        getData().addLine("");
                        getData().addLine("string result = argSource;");
                        getData().addLine("for (;;) {");
                        getData().addLine(
                                "if (GetBytesLength(result) >= argLength) {");
                        getData().addLine("break;");
                        getData().addLine("}");
                        getData().addLine("");
                        getData().addLine("// 一文字ずつ増やしていきます。");
                        getData().addLine("result = result + argPadChar;");
                        getData().addLine("}");
                        getData().addLine("return result;");
                    }
                });

                addMethod(new MethodExpander("PadLeft") {
                    protected boolean isStatic() {
                        return true;
                    }

                    public void setupSignature() {
                        getJavaDoc().addLine("与えられた文字列を指定の長さまで左側をパディングします。");

                        getJavaDoc().addParameter("argSource", "入力文字列。");
                        addArgument(new Value(new Type("string"), "argSource"));

                        getJavaDoc()
                                .addParameter("argLength", "目標とするトータルバイト長。");
                        addArgument(new Value(new Type("int"), "argLength"));

                        getJavaDoc().addParameter("argPadChar",
                                "埋める際に利用するパディング文字。");
                        addArgument(new Value(new Type("char"), "argPadChar"));

                        getJavaDoc().addReturn("目標となるバイト長に加工された後の文字列。");
                        setReturnType(new Type("string"));
                    }

                    public void implement() {
                        getData().addLine("if (argSource == null) {");
                        getData()
                                .addLine(
                                        "throw new ArgumentException(\"PadLeftの入力文字列に nullが与えられました。\");");
                        getData().addLine("}");
                        getData().addLine("");
                        getData().addLine("string result = argSource;");
                        getData().addLine("for (;;) {");
                        getData().addLine(
                                "if (GetBytesLength(result) >= argLength) {");
                        getData().addLine("break;");
                        getData().addLine("}");
                        getData().addLine("");
                        getData().addLine("// 一文字ずつ増やしていきます。");
                        getData().addLine("result = argPadChar + result;");
                        getData().addLine("}");
                        getData().addLine("return result;");
                    }
                });

                addMethod(new MethodExpander("GetBytesLength") {
                    protected Scope getScope() {
                        return Scope.PRIVATE;
                    }

                    protected boolean isStatic() {
                        return true;
                    }

                    public void setupSignature() {
                        getJavaDoc().addLine("与えられた文字列のバイト長を取得します。");

                        getJavaDoc().addParameter("argSource", "入力文字列。");
                        addArgument(new Value(new Type("string"), "argSource"));

                        getJavaDoc().addReturn("入力文字列のバイト長。");
                        setReturnType(new Type("int"));
                    }

                    public void implement() {
                        getData().addLine("if (argSource == null) {");
                        getData()
                                .addLine(
                                        "throw new ArgumentException(\"GetBytesLengthの入力文字列に nullが与えられました。\");");
                        getData().addLine("}");
                        getData().addLine("return GetBytes(argSource).Length;");
                    }
                });

                addMethod(new MethodExpander("GetBytes") {
                    protected boolean isStatic() {
                        return true;
                    }

                    public void setupSignature() {
                        getJavaDoc().addLine("文字列をバイト配列に変換します。");
                        getJavaDoc().addParameter("inputString", "変換元の文字列。");
                        addArgument(new IgValue(new IgType("string"),
                                "inputString"));
                        getJavaDoc().addReturn("バイト配列に変換後の文字列。");
                        setReturnType(new IgType("byte[]"));
                    }

                    public void implement() {
                        getData().addLine("if (inputString == null)");
                        getData().addLine("{");
                        getData()
                                .addLine(
                                        "throw new ArgumentException(\"GetBytesメソッドにnullが与えられました。\");");
                        getData().addLine("}");

                        getData().addLine("// 文字列をバイト配列に変換します。");
                        getData()
                                .addLine(
                                        "byte[] inputBytes = Encoding.Unicode.GetBytes(inputString);");
                        getData()
                                .addLine(
                                        "// エンコーディングを取得します。ここではシフトJISへのエンコーディングを取得しています。");
                        getData()
                                .addLine("//TODO: 定義書で指定されているエンコードをする必要があります。");
                        getData()
                                .addLine(
                                        "Encoding targetEncoding = Encoding.GetEncoding(932);");
                        getData().addLine("// 実際にコードを変換。");
                        getData()
                                .addLine(
                                        "return Encoding.Convert(Encoding.Unicode, targetEncoding, inputBytes);");
                    }
                });
            }
        };

        ClassExpander.generateCsSource(classExpander, directoryTarget);
    }
}
