/*
 * Copyright (C) 2010 The Android-X86 Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: Yi Sun <beyounn@gmail.com>
 */

package com.maxwell.net.ethernet;

import java.util.List;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Slog;

/**
 * This class provides the primary API for managing all aspects of Ethernet
 * connectivity. Get an instance of this class by calling
 * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.ETHERNET_SERVICE)}.
 *
 * This is the API to use when performing Ethernet specific operations. To
 * perform operations that pertain to network connectivity at an abstract
 * level, use {@link android.net.ConnectivityManager}.
 */
public class EthernetManager {
    public static final String TAG = "EthernetManager";
    private static final boolean localLOGV = false;
    public static final int ETHERNET_DEVICE_SCAN_RESULT_READY = 0;
    public static final String ETHERNET_STATE_CHANGED_ACTION =
        "com.maxwell.net.ethernet.ETHERNET_STATE_CHANGED";
    public static final String NETWORK_STATE_CHANGED_ACTION =
        "com.maxwell.net.ethernet.STATE_CHANGE";
    public static final String ETHERNET_CHECKBOX_CHANGED_ACTION =
        "com.maxwell.net.ethernet.ETHERNET_CHECKBOX_CHANGED_ACTION";
    public static final String ETHERNET_MONITOR_RESULT =
        "com.maxwell.net.ethernet.ETHERNET_MONITOR_RESULT";
    public static final String ETHERNET_SYSTEM_UI_NOTIFICATION_CHANGED_ACTION =
        "com.maxwell.net.ethernet.ETHERNET_SYSTEM_UI_NOTIFICATION_CHANGED_ACTION";
    public static final String ETHERNET_BOOT_COMPLETED_ACTION =
        "android.intent.action.BOOT_COMPLETED";

    public static final String EXTRA_NETWORK_INFO = "networkInfo";
    public static final String EXTRA_ETHERNET_STATE = "ETHERNET_state";
    public static final String EXTRA_PREVIOUS_ETHERNET_STATE = "previous_ETHERNET_state";
    public static final int EVENT_DHCP_START                        = 0;
    public static final int EVENT_INTERFACE_CONFIGURATION_SUCCEEDED = 1;
    public static final int EVENT_INTERFACE_CONFIGURATION_FAILED    = 2;
    public static final int EVENT_HW_CONNECTED                      = 3;
    public static final int EVENT_HW_DISCONNECTED                   = 4;
    public static final int EVENT_HW_PHYCONNECTED                   = 5;
    private static final int NOTIFY_ID                              = 6;
    public static final int EVENT_DHCP_RECONNECT                   = 7;
    public static final int EVENT_DHCP_FAILED                      = 8;
    public static final int EVENT_DEFERRED_PHY_STATE               = 9;
    public static final int EVENT_RENEW_DHCP = 10;

    /**
     * The lookup key for a {@link android.net.LinkProperties} object associated with the
     * Ethernet network. Retrieve with
     * {@link android.content.Intent#getParcelableExtra(String)}.
     * @hide
     */
    public static final String EXTRA_LINK_PROPERTIES = "linkProperties";

    /**
     * The lookup key for a {@link android.net.LinkCapabilities} object associated with the
     * Ethernet network. Retrieve with
     * {@link android.content.Intent#getParcelableExtra(String)}.
     * @hide
     */
    public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities";

    public static final int ETHERNET_STATE_UNKNOWN = 0;
    public static final int ETHERNET_STATE_DISABLED = 1;
    public static final int ETHERNET_STATE_ENABLED = 2;
    public static final int ETHERNET_STATE_PCPORT_ETHERNET_ENABLED = 3;
    public static final int ETHERNET_STATE_PCPORT_ETHERNET_DISABLED = 4;

    public static final int ETHERNET_STATE_ENABLING = 5;
    public static final int ETHERNET_STATE_DISABLING = 6;
    public static final int ETHERNET_LINK_DOWN = 7;
    public static final int ETHERNET_DHCP_IP_ERROR = 8;
    public static final int ETHERNET_STATIC_IP_ERROR = 9;
    public static final int ETHERNET_STATIC_IP_CONFIGURING = 10;
    public static final int ETHERNET_DHCP_IP_CONFIGURING = 11;
    public static final int ETHERNET_IP_CONF_SUCCESS = 12;

    public static final int ETHERNET_FIRST_BOOT_STATUS_OFF = 0;
    public static final int ETHERNET_FIRST_BOOT_STATUS_ON = 1;

    /** @hide */
    public static final int DATA_ACTIVITY_NONE         = 0x00;
    /** @hide */
    public static final int DATA_ACTIVITY_IN           = 0x01;
    /** @hide */
    public static final int DATA_ACTIVITY_OUT          = 0x02;
    /** @hide */
    public static final int DATA_ACTIVITY_INOUT        = 0x03;

    IEthernetManager mService;
    Handler mHandler;

    public EthernetManager(IEthernetManager service, Handler handler) {
        Slog.i(TAG, "Init Ethernet Manager, service: " +service);
        mService = service;
        mHandler = handler;
    }

    /**
     * check if the ethernet service has been configured.
     * @return {@code true} if configured {@code false} otherwise
     */
    public boolean isConfigured() {
        try {
            return mService.isConfigured();
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not check eth config state");
        }
        return false;
    }

    /**
     * Return the saved ethernet configuration
     * @return ethernet interface configuration on success, {@code null} on failure
     */
    public EthernetDevInfo getSavedConfig() {
        try {
            return mService.getSavedConfig();
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not get eth config");
        }
        return null;
    }

    /**
     * update a ethernet interface information
     * @param info  the interface infomation
     */
    public boolean updateDevInfo(EthernetDevInfo info) {
        try {
            return mService.updateDevInfo(info);
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not update ethernet device info");
            return false;
        }
    }

    /**
     * get all the ethernet device names
     * @return interface name list on success, {@code null} on failure
     */
    public String[] getDeviceNameList() {
        try {
            return mService.getDeviceNameList();
        } catch (RemoteException e) {
            return null;
        }
    }
    /**
     * Enable or Disable a ethernet service
     * @param enable {@code true} to enable, {@code false} to disable
     * @hide
     */
    public void setEnabled(boolean enable) {
        try {
            mService.setState(enable ? ETHERNET_STATE_ENABLED:ETHERNET_STATE_DISABLED);
        } catch (RemoteException e) {
            Slog.e(TAG,"Can not set new state");
        }
    }

	 /**
     * Enable or Disable a PC port ethernet service
     * @param enable {@code true} to enable, {@code false} to disable
     * @hide
     */
    public void setPCEthEnabled(boolean enable) {
        try {
            mService.setState(enable ? ETHERNET_STATE_PCPORT_ETHERNET_ENABLED:ETHERNET_STATE_PCPORT_ETHERNET_DISABLED);
        } catch (RemoteException e) {
            Slog.e(TAG,"Can not set new state");
        }
    }
    /**
     * Get ethernet service state
     * @return the state of the ethernet service
     */
    public int getState( ) {
        try {
            return mService.getState();
        } catch (RemoteException e) {
            return 0;
        }
    }

    /**
     * Get ethernet Intermediate state
     * @return the state of the ethernet service
     */
    public int getIntState( ) {
        try {
            return mService.getIntState();
        } catch (RemoteException e) {
            return 0;
        }
    }

    /**
     * get the number of ethernet interfaces in the system
     * @return the number of ethernet interfaces
     */
    public int getTotalInterface() {
        try {
            return mService.getTotalInterface();
        } catch (RemoteException e) {
            return 0;
        }
    }

    /**
     * @hide
     */
    public void setDefaultConf() {
        try {
            mService.setMode(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP);
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not set default conf");
        }
    }

    /**
     * setMode
     *  @param mode Ethernet mode
     */
    public void setMode(String mode) {
        try {
            mService.setMode(mode);
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not set the modee");
        }
    }

    /**
     * getMode
     * @return Ethernet mode
     */
    public String getMode() {
        try {
            return mService.getMode();
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not get mode");
        }
        return null;
    }

    /**
     * setNetType
     *  @param nettype Ethernet nettype @ipv4 or @ipv6
     */
    public void setNettype(String nettype) {
        try {
            mService.setNetType(nettype);
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not set the nettype");
        }
    }

    /**
     * getNetType
     * @return Ethernet nettype @ipv4 or @ipv6
     */
    public String getNetType() {
        try {
            return mService.getNetType();
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not get nettype");
        }
        return null;
    }

    /**
     * resetInterface
     */
    public void resetInterface() {
        try {
            mService.resetInterface();
        } catch (RemoteException e) {
            Slog.e(TAG, "Can not reset interface");
        }
    }

    /**
     * clearIPAddress
     */
    public void clearIPAddress() {
        try {
            mService.clearIPAddress();
        } catch (RemoteException e) {
            Slog.e(TAG, "clearIP Address is failed");
        }
    }

    /**
     * Request to reconnnect the already torn down ETH
     */
    public boolean startEth() {
        try {
            return mService.startEth();
        } catch (RemoteException e) {
            Slog.e(TAG, "startEth is failed");
        }
        return false;
    }

    /**
     * Request to tear down the ETH
     */
    public boolean stopEth() {
        try {
            return mService.stopEth();
        } catch (RemoteException e) {
            Slog.e(TAG, "stopEth is failed");
        }
        return false;
    }

    /**
     * It is a silent way of restarting dsdt service alone
     * Note :: Right now, it is used in vlan scenarios
     * If vlan parameters are modified in,
     *   1) Ethernet is on in UI, but cable is unplugged
     */
    public boolean restartDSDT() {
        try {
            return mService.restartDSDT();
        } catch (RemoteException e) {
            Slog.e(TAG, "restartDSDT is failed");
        }
        return false;
    }
}
