package org.maachang.util.net;

import java.util.List;

import org.maachang.util.StringUtil;

/**
 * ネットワークアドレス取得BSD系UNIX版. <BR>
 * <BR>
 * BSD版のネットワークアドレス取得処理です.
 * 
 * @version 2008/10/28
 * @author masahito suzuki
 * @since MaachangBase 1.08
 */
class NetAdapterByBsd extends AbstractNetAdapter {
    /**
     * IPアドレス取得コマンド.
     */
    private static final String IPCONFIG_COMMAND = "ifconfig -a";

    /**
     * 媒体開始文字.
     */
    private static final String ADAPTER_NAME_1 = "flags";
    private static final String ADAPTER_NAME_2 = "=";

    /**
     * IPアドレス区切り値.
     */
    private static final char DIV_IP_CODE = '.';

    /**
     * macアドレス区切り値.
     */
    private static final char DIV_MAC_CODE = ':';

    /**
     * IPアドレス.
     */
    private static final String IP_ADDR = "inet";

    /**
     * サブネットマスク.
     */
    private static final String SUB_NET = "netmask";

    /**
     * macアドレス.
     */
    private static final String MAC_ADDR = "ether";

    /**
     * サブネットマスクヘッダ.
     */
    private static final String SUB_NET_HEADER = "0x";

    /**
     * コンストラクタ.
     */
    public NetAdapterByBsd() {
        init();
    }

    /**
     * ネットワーク情報取得処理.
     * 
     * @exception Exception
     *                例外.
     */
    public void load() throws Exception {
        int i, j;
        int len;
        int lenJ;
        int pnt;
        int off;
        int st, et;
        int localCheck;
        char code;
        List<String> cmdOut = null;
        String name = null;
        String value = null;
        try {

            this.clear();
            cmdOut = super.runExec(NetAdapterByBsd.IPCONFIG_COMMAND);
            len = cmdOut.size();
            for (i = 0, localCheck = 0; i < len; i++) {
                String bcmd = cmdOut.get(i);
                String cmd = bcmd.toLowerCase() ;
                // adapter名を調べる.
                if ((off = cmd.indexOf(NetAdapterByBsd.ADAPTER_NAME_1)) != -1
                        && cmd.indexOf(NetAdapterByBsd.ADAPTER_NAME_2, off) != -1) {
                    pnt = off;

                    name = StringUtil.trim(bcmd.substring(0, cmd
                            .indexOf(NetAdapterByBsd.DIV_MAC_CODE)));

                }
                // IPアドレスの場合.
                if ((pnt = cmd.indexOf(NetAdapterByBsd.IP_ADDR)) != -1) {

                    pnt = pnt + NetAdapterByBsd.IP_ADDR.length();
                    lenJ = cmd.length();

                    for (j = pnt, st = -1, et = -1; j < lenJ; j++) {

                        code = cmd.charAt(j);

                        if (st == -1) {
                            if (code >= '0' && code <= '9') {
                                st = j;
                            }
                        } else if (code == NetAdapterByBsd.DIV_IP_CODE
                                || (code >= '0' && code <= '9')) {
                            et = j;
                        } else {
                            break;
                        }

                    }

                    value = StringUtil.trim(bcmd.substring(st, et + 1));

                    // 対象IPアドレスがローカルアドレスを示す場合.
                    if (value.equals(LOCAL_IP) == true) {
                        localCheck++;
                    }

                    super.setIpAddress(name, value);
                }
                // サブネットマスクの場合.
                if ((off = cmd.indexOf(NetAdapterByBsd.SUB_NET)) != -1) {

                    if ((pnt = cmd.indexOf(NetAdapterByBsd.SUB_NET_HEADER, off)) != -1) {
                        pnt = pnt + NetAdapterByBsd.SUB_NET_HEADER.length();
                    } else {
                        pnt = off + NetAdapterByBsd.SUB_NET.length();
                    }

                    lenJ = cmd.length();

                    for (j = pnt, st = -1, et = -1; j < lenJ; j++) {

                        code = cmd.charAt(j);

                        if (st == -1) {
                            if ((code >= '0' && code <= '9')
                                    || (code >= 'a' && code <= 'f')) {
                                st = j;
                            }
                        } else if ((code >= '0' && code <= '9')
                                || (code >= 'a' && code <= 'f')) {
                            et = j;
                        } else {
                            break;
                        }

                    }

                    value = StringUtil.trim(StringUtil.changeString(bcmd
                            .substring(st, et + 1), NetAdapterByBsd.SUB_NET,
                            " "));

                    super.setSubnetMask(name, NetAdapterByBsd
                            .convertStringByIpAddress(value));
                }
                // MACアドレスの場合.
                if ((pnt = cmd.indexOf(NetAdapterByBsd.MAC_ADDR)) != -1) {
                    pnt = pnt + NetAdapterByBsd.MAC_ADDR.length();
                    lenJ = cmd.length();

                    for (j = pnt, st = -1, et = -1; j < lenJ; j++) {

                        code = cmd.charAt(j);

                        if (st == -1) {
                            if ((code >= '0' && code <= '9')
                                    || (code >= 'a' && code <= 'f')) {
                                st = j;
                            }
                        } else if (code == NetAdapterByBsd.DIV_MAC_CODE
                                || (code >= '0' && code <= '9')
                                || (code >= 'a' && code <= 'f')) {
                            et = j;
                        } else {
                            break;
                        }
                    }
                    value = StringUtil.trim(bcmd.substring(st, et + 1))
                            .toUpperCase();
                    super.setMacAddress(name, value);
                }

            }
            // ローカルアドレスが存在しない場合.
            if (localCheck == 0) {
                // アドレスを追加.
                super.setIpAddress(AbstractNetAdapter.DEFAULT_ETHER_NAME, LOCAL_IP);
                // ホスト名を追加.
                super.setSubnetMask(AbstractNetAdapter.DEFAULT_ETHER_NAME,
                        AbstractNetAdapter.LO_HOST_SUB);
            }
        } catch (Exception e) {
            this.clear();
            throw e;
        } finally {
            cmdOut = null;
            name = null;
            value = null;
        }
    }

    /**
     * サブネットマスクをIPアドレス形式に変換.
     */
    private static final String convertStringByIpAddress(String code) {
        int i;
        int len;
        byte[] bin = null;
        StringBuilder buf = null;
        String ret = null;
        buf = new StringBuilder();
        try {
            bin = convertString16ToBinary(code.toUpperCase());

            len = bin.length;
            for (i = 0; i < len; i++) {
                if (i != 0) {
                    buf.append(NetAdapterByBsd.DIV_IP_CODE);
                }
                buf.append((int) (bin[i] & 0x000000ff));
            }

            ret = buf.toString();

        } catch (Exception t) {
            ret = "0.0.0.0";
        } finally {
            bin = null;
            buf = null;
        }

        return ret;

    }
}
