/*
 * blanco Framework
 * Copyright (C) 2004-2008 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.svnconf;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;

import blanco.commons.util.BlancoFileUtil;
import blanco.commons.util.BlancoStringUtil;
import blanco.svnconf.message.BlancoSvnConfMessage;
import blanco.svnconf.valueobject.BlancoSvnConfStructure;

/**
 * 「Subversionリポジトリ定義書」Excel様式からApache用 confファイルを生成。
 * 
 * このクラスは、中間XMLファイルから設定ファイルを自動生成する機能を担います。
 * 
 * @author IGA Tosiki
 */
public class BlancoSvnConfXml2ApacheConfFile {
    public static final String CMDLINE_PREFIX = "svnconf: ";

    /**
     * メッセージ定義。
     */
    protected final BlancoSvnConfMessage fMsg = new BlancoSvnConfMessage();

    /**
     * 自動生成するソースファイルの文字エンコーディング。
     */
    private String fEncoding = null;

    public void setEncoding(final String argEncoding) {
        fEncoding = argEncoding;
    }

    /**
     * 指定のシートの記述内容を展開します。
     * 
     * @param argStructures
     *            タスクの構造の配列。
     * @param argDirectoryTarget
     *            出力先ディレクトリ
     */
    public void structures2File(final BlancoSvnConfStructure[] argStructures,
            final File argDirectoryTarget) {
        final File dirBlancoApacheConf = new File(argDirectoryTarget
                .getAbsolutePath()
                + "/apache.conf/extra");
        dirBlancoApacheConf.mkdirs();
        final File fileApacheConf = new File(dirBlancoApacheConf
                .getAbsolutePath()
                + "/httpd-svn.conf");
        expandApacheConf(argStructures, fileApacheConf);
    }

    /**
     * Apache HTTP Server用の設定ファイルを生成します。
     * 
     * @param argStructures
     *            構造体情報の配列。
     * @param argTarget
     *            出力先ファイル。
     */
    private void expandApacheConf(final BlancoSvnConfStructure[] argStructures,
            final File argTarget) {
        if (argStructures.length == 0) {
            // 一件もありません。
            return;
        }

        final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        try {
            BufferedWriter writer = null;
            if (BlancoStringUtil.null2Blank(fEncoding).length() == 0) {
                writer = new BufferedWriter(new OutputStreamWriter(outStream));
            } else {
                writer = new BufferedWriter(new OutputStreamWriter(outStream,
                        fEncoding));
            }

            writeHead(argStructures, writer);
            writer.newLine();

            writeBody(argStructures, writer);

            writeEndOfFile(writer);

            writer.close();
        } catch (IOException ex) {
            // 無視
            ex.printStackTrace();
        }

        try {
            switch (BlancoFileUtil.bytes2FileIfNecessary(outStream
                    .toByteArray(), argTarget)) {
            case 1:
                System.out.println(CMDLINE_PREFIX + "create: "
                        + argTarget.getAbsolutePath());
                break;
            case 2:
                System.out.println(CMDLINE_PREFIX + "update: "
                        + argTarget.getAbsolutePath());
                break;
            }
        } catch (IOException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        }
    }

    /**
     * 設定ファイルヘッド領域の書き出し。
     * 
     * @param argStructures
     *            構造体情報の配列。
     * @param writer
     *            出力先ライター。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    private void writeHead(final BlancoSvnConfStructure[] argStructures,
            final BufferedWriter writer) throws IOException {
        writer
                .write("############################################################");
        writer.newLine();
        writer.write("# <<apache>/conf/extra/httpd-svn.conf>");
        writer.newLine();
        writer.write("#");
        writer.newLine();
        writer.write("# Subversionリポジトリ定義。");
        writer.newLine();
        writer.write("#");
        writer.newLine();
        writer.write("# ホスト名: " + argStructures[0].getHostname());
        writer.newLine();
        writer.write("#");
        writer.newLine();
        writer.write("# このファイルを有効化するためには、Apache の httpd.conf ファイルに以下の行を追加します。");
        writer.newLine();
        writer.write("# Include conf/extra/httpd-svn.conf");
        writer.newLine();
        writer
                .write("############################################################");
        writer.newLine();
    }

    /**
     * 設定ファイル本体領域の書き出し。
     * 
     * @param argStructures
     *            構造体情報の配列。
     * @param writer
     *            出力先ライター。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    private void writeBody(final BlancoSvnConfStructure[] argStructures,
            final BufferedWriter writer) throws IOException {
        BlancoSvnConfStructure pastStructure = null;
        for (int index = 0; index < argStructures.length; index++) {
            if (pastStructure == null) {
                pastStructure = argStructures[index];
            }
            if (pastStructure.getHostname().equals(
                    argStructures[index].getHostname()) == false) {
                // ホスト名違いを発見。
                throw new IllegalArgumentException(fMsg.getMbsvnc07(
                        pastStructure.getName(), pastStructure.getHostname(),
                        argStructures[index].getName(), argStructures[index]
                                .getHostname()));
            }

            writer.write("########################################");
            writer.newLine();
            writer.write("# リポジトリ定義ID: " + argStructures[index].getName());
            writer.newLine();
            writer.write("# 想定URL: http://"
                    + argStructures[index].getHostname() + "/svn/"
                    + argStructures[index].getName() + "/");
            writer.newLine();
            if (BlancoStringUtil.null2Blank(
                    argStructures[index].getDescription()).length() > 0) {
                writer.write("# 説明: " + argStructures[index].getDescription());
                writer.newLine();
            }

            writer.write("<Location /svn/" + argStructures[index].getName()
                    + ">");
            writer.newLine();

            writer.write("    DAV                svn");
            writer.newLine();
            writer.write("    SVNPath            \""
                    + argStructures[index].getBaseDirectory() + "/"
                    + argStructures[index].getName() + "\"");
            writer.newLine();
            writer.write("    AuthzSVNAccessFile \""
                    + argStructures[index].getBaseDirectory() + ".conf/"
                    + argStructures[index].getName() + ".svnauthz\"");
            writer.newLine();
            writer.write("</Location>");
            writer.newLine();
            writer.newLine();
        }
    }

    /**
     * end of file 領域の書き出し。
     * 
     * @param writer
     *            出力先ライター。
     * @throws IOException
     *             入出力例外が発生した場合。
     */
    private void writeEndOfFile(final BufferedWriter writer) throws IOException {
        writer.write("####################");
        writer.newLine();
        writer.write("# end of file");
        writer.newLine();
        writer.write("####################");
        writer.newLine();
    }
}
