package org.maachang.util.net;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.maachang.util.FileUtil;
import org.maachang.util.Os;
import org.maachang.util.RunProcess;

/**
 * IPアドレス変更.
 * <p>この処理を実施する場合、ROOT権限をもつユーザで実施してください.</p>
 * 
 * @version 2008/10/28
 * @author masahito suzuki
 * @since MaachangBase 1.08
 */
public abstract class ChangeIp {
    private ChangeIp() {}
    
    /**
     * LOG.
     */
    private static final Log LOG = LogFactory.getLog( ChangeIp.class ) ;
    
    /**
     * 同期用.
     */
    private static final Object sync = new Object() ;
    
    /**
     * IPアドレス変更.
     * @param name 変更ネットワーク名を設定します.
     * @param addr 変更後のアドレスを設定します.
     * @param mask 変更後のネットマスクを設定します.
     * @param gateway 変更後のデフォルトゲートウェイを設定します.
     * @param dns 変更後のDNSを設定します.
     * @exception Exception 例外.
     */
    public static final void change( String name,String addr,String mask,String gateway,String dns )
        throws Exception {
        if( name == null || ( name = name.trim() ).length() <= 0 ||
            addr == null || ( addr = addr.trim() ).length() <= 0 ||
            mask == null || ( mask = mask.trim() ).length() <= 0 ) {
            throw new IllegalArgumentException( "引数は不正です" ) ;
        }
        synchronized( sync ) {
            String[] cmd ;
            switch( Os.getInstance().getOS() ) {
                case Os.OS_WINNT :
                    // windowsは、netshコマンドで、ネットワークを変更する.
                    StringBuilder b = new StringBuilder() ;
                    b.append( "netsh interface ip set address \"" ).
                    append( name ).append( "\" static " ).append( addr ).
                    append( " " ).append( mask ) ;
                    if( gateway != null && ( gateway = gateway.trim() ).length() > 0 ) {
                        b.append( " " ).append( gateway ).append( " 1 " ) ;
                    }
                    else {
                        b.append( " none " ) ;
                    }
                    if( dns != null && ( dns = dns.trim() ).length() > 0 ) {
                        b.append( "& ").append( "netsh interface ip set dns \"" ).
                        append( name ).append( "\" static " ).append( dns ) ;
                    }
                    cmd = new String[] { "cmd","/c",b.toString() } ;
                    break ;
                case Os.OS_UNIX :
                case Os.OS_MAC_OS_X :
                    // linuxの場合、/etc/sysconfig/network-scripts/ifcfg-xxx
                    // の編集及び、/etc/resolv.conf
                    // の編集を行った後、
                    // /sbin/service network restart
                    // でネットワーク再起動を行う.
                    cmd = new String[]{ "/bin/sh","-c","/sbin/service network restart" } ;
                    // ifcfg-xxxの編集.
                    changeIfCfg( name,addr,mask,gateway ) ;
                    // resolv.confの編集.
                    changeResolv( dns ) ;
                    break ;
                default :
                    throw new IOException( "実行中のOSでは利用できません" ) ;
            }
            RunProcess runProc = new RunProcess( cmd ) ;
            try {
                BufferedReader reader = new BufferedReader( new InputStreamReader( runProc.execution() ) ) ;
                for( int i = 1 ;; i ++ ) {
                    String s = reader.readLine() ;
                    if( s == null ) {
                        break ;
                    }
                    LOG.info( "[ChangeIp(行:" + i + ")]:" + s ) ;
                }
                runProc.waitFor() ;
            } finally {
                runProc.destroy() ;
            }
        }
    }
    
    /**
     * ifcfg-XXXの編集.
     * [Linux用].
     */
    private static final void changeIfCfg( String name,String addr,String mask,String gateway )
        throws Exception {
        if( gateway == null || ( gateway = gateway.trim() ).length() <= 0 ) {
            gateway = null ;
        }
        String fileName = "/etc/sysconfig/network-scripts/ifcfg-" + name ;
        if( FileUtil.isFileExists( fileName ) == false ) {
            throw new IOException( "NetworkConfig(" + fileName + ")は存在しません" ) ;
        }
        // バックアップファイルを作成.
        byte[] b = FileUtil.getFile( fileName ) ;
        FileUtil.setFile( "/etc/sysconfig/network-scripts/back.ifcfg-" + name,true,b ) ;
        b = null ;
        // １行毎に情報を取得して、当てはまる条件が存在した場合、
        // その内容に割り当てなおす.
        StringBuilder buf = new StringBuilder() ;
        BufferedReader reader = null ;
        try {
            reader = new BufferedReader( new InputStreamReader( new FileInputStream( fileName ) ) ) ;
            boolean mkFlg = false ;
            boolean gwFlg = false ;
            for( int i = 0 ;; i ++ ) {
                if( i != 0 ) {
                    buf.append( "\n" ) ;
                }
                String s = reader.readLine() ;
                if( s == null ) {
                    break ;
                }
                String x = s.toLowerCase() ;
                if( x.startsWith( "ipaddr=" ) ) {
                    buf.append( "IPADDR=" ).append( addr ) ;
                }
                else if( x.startsWith( "netmask=" ) ) {
                    buf.append( "NETMASK=" ).append( mask ) ;
                    mkFlg = true ;
                }
                else if( x.startsWith( "gateway=" ) ) {
                    if( gateway != null ) {
                        buf.append( "GATEWAY=" ).append( gateway ) ;
                        gwFlg = true ;
                    }
                }
                else if( s.length() > 0 ) {
                    buf.append( s ) ;
                }
            }
            reader.close() ;
            reader = null ;
            if( mkFlg == false ) {
                buf.append( "\nNETMASK=" ).append( mask ) ;
            }
            if( gwFlg == false && gateway != null ) {
                buf.append( "\nGATEWAY=" ).append( gateway ) ;
            }
            FileUtil.setFileByString( fileName,true,buf.toString(),System.getProperty("file.encoding") ) ;
        } finally {
            if( reader != null ) {
                try {
                    reader.close() ;
                } catch( Exception e ) {
                }
            }
        }
    }
    
    /**
     * DNS変更.
     * [Linux用].
     */
    private static final void changeResolv( String dns )
        throws Exception {
        if( dns != null ) {
            if( ( dns = dns.trim() ).length() <= 0 ) {
                dns = null ;
            }
        }
        String fileName =  "/etc/resolv.conf" ;
        if( FileUtil.isFileExists( fileName ) == false ) {
            // ファイルが存在しない場合は作成する.
            FileUtil.setFileByString( fileName,true,
                new StringBuilder().append( "nameserver " ).append( dns ).toString(),
                System.getProperty("file.encoding") ) ;
            return ;
        }
        // バックアップファイルを作成.
        byte[] b = FileUtil.getFile( fileName ) ;
        FileUtil.setFile( fileName + ".back",true,b ) ;
        b = null ;
        // １行毎に情報を取得して、当てはまる条件が存在した場合、
        // その内容に割り当てなおす.
        StringBuilder buf = new StringBuilder() ;
        BufferedReader reader = null ;
        try {
            reader = new BufferedReader( new InputStreamReader( new FileInputStream( fileName ) ) ) ;
            boolean dnsFlg = false ;
            for( int i = 0 ;; i ++ ) {
                if( i != 0 ) {
                    buf.append( "\n" ) ;
                }
                String s = reader.readLine() ;
                if( s == null ) {
                    break ;
                }
                String x = s.toLowerCase() ;
                if( x.startsWith( "nameserver " ) ) {
                    if( dns != null ) {
                        buf.append( "nameserver " ).append( dns ) ;
                        dnsFlg = true ;
                    }
                }
                else if( s.length() > 0 ) {
                    buf.append( s ) ;
                }
            }
            reader.close() ;
            reader = null ;
            if( dnsFlg == false && dns != null ) {
                buf.append( "\nnameserver " ).append( dns ) ;
            }
            FileUtil.setFileByString( fileName,true,buf.toString(),System.getProperty("file.encoding") ) ;
        } finally {
            if( reader != null ) {
                try {
                    reader.close() ;
                } catch( Exception e ) {
                }
            }
        }
    }
    
    /** テスト **/
    public static final void main( String[] args ) throws Exception {
        if( args.length < 5 ) {
            System.out.println( "illegal error." ) ;
            System.out.println( "1: netName 2: addr 3: mask 4: gateway 5: dns" ) ;
            return ;
        }
        change( args[ 0 ],args[ 1 ],args[ 2 ],args[ 3 ],args[ 4 ] ) ;
    }
    
}
