/*
 * 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 android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.ConnectivityManager;
import android.net.NetworkStateTracker;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.os.ServiceManager;
import android.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Track the state of Ethernet connectivity. All event handling is done here,
 * and all changes in connectivity state are initiated here.
 *
 * @hide
 */

public class EthernetStateTracker implements NetworkStateTracker {
    private static final String TAG = "EthernetStateTracker";
    private static final boolean localLOGV = false;

    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);

    private EthernetManager mEM;
    private boolean mServiceStarted;
    private NetworkInfo mNetworkInfo;
    private LinkProperties mLinkProperties;
    private BroadcastReceiver mEthernetStateReceiver;
    private Context mContext;

    /* For sending events to connectivity service handler */
    private Handler mCsHandler;

    public EthernetStateTracker(Context context, Handler target) {
        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, "ETH", "");
        mLinkProperties = new LinkProperties();
        if (localLOGV) Slog.v(TAG, "Starts EthernetStateTracker...");

        mServiceStarted = true;

        mNetworkInfo.setIsAvailable(false);
        setTeardownRequested(false);
    }

    @Override
    public String getTcpBufferSizesPropName() {
        return "net.tcp.buffersize.default";
    }

    @Override
    public boolean isAvailable() {
        return mNetworkInfo.isAvailable();
    }

    @Override
    public boolean teardown() {
        if (localLOGV) Slog.v(TAG,"teardown called for ETH");
	mTeardownRequested.set(true);
        boolean ret = mEM.stopEth(); 
        return ret;
    }

    @Override
    public boolean reconnect() {
        if (localLOGV) Slog.v(TAG,"reconnect called for ETH");
        mTeardownRequested.set(false);
        boolean ret = mEM.startEth();
        return ret; 
    }

    @Override
    public boolean setRadio(boolean turnOn) {
        return true;
    }

    @Override
    public void startMonitoring(Context context, Handler target) {
        if (localLOGV) Slog.v(TAG,"start to monitor the ethernet devices");
	if (mServiceStarted) {
            mEM = (EthernetManager)context.getSystemService(Context.ETHERNET_SERVICE);
	    mContext = context;
	    mCsHandler = target;

	    /*Register Broastcast receiver for System UI notification */
	    IntentFilter filter = new IntentFilter();
	    filter.addAction(EthernetManager.ETHERNET_STATE_CHANGED_ACTION);

	    mEthernetStateReceiver = new EthernetStateReceiver();
	    mContext.registerReceiver(mEthernetStateReceiver, filter);
	}
    }


    public void setDependencyMet(boolean met) {
        //not supported on this network
    }

    public void setUserDataEnable(boolean enabled) {
        //not supported on this network
    }

    public void setDataEnable(boolean enabled) {
        //not supported on this network
    }

    public void setPolicyDataEnable(boolean enabled) {
        //not supported on this network
    }

    public void setTeardownRequested(boolean isRequested) {
        mTeardownRequested.set(isRequested);
    }

    public boolean isTeardownRequested() {
        return mTeardownRequested.get();
    }

    private void postNotification(int event) {
        Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
        msg.sendToTarget();
    }

    /*Broastcast receiver for System UI notification*/
    private class EthernetStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent != null){
                if (intent.getAction().equals(EthernetManager.ETHERNET_STATE_CHANGED_ACTION)) {
                    int event = intent.getExtras().getInt("EthEvent");
                    mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
                          EthernetManager.EXTRA_NETWORK_INFO);
                    mLinkProperties = (LinkProperties)intent.getParcelableExtra(
                        EthernetManager.EXTRA_LINK_PROPERTIES);
                    if (mLinkProperties == null) {
                        mLinkProperties = new LinkProperties();
                    }
                    Slog.d(TAG,"Broadcast Ethernet status" + mNetworkInfo + mLinkProperties + event);
                    postNotification(event);
                }
            }            
        }
    }

    /**
     * Check if private DNS route is set for the network
     */
    public boolean isPrivateDnsRouteSet() {
        return mPrivateDnsRouteSet.get();
    }

    /**
     * Set a flag indicating private DNS route is set
     */
    public void privateDnsRouteSet(boolean enabled) {
        mPrivateDnsRouteSet.set(enabled);
    }

    /**
     * Fetch NetworkInfo for the network
     */
    public NetworkInfo getNetworkInfo() {
        if(localLOGV) Slog.v(TAG, "EthernetStateTracker :: getNetworkInfo" + mNetworkInfo);
        return new NetworkInfo(mNetworkInfo);
    }

    /**
     * Fetch LinkProperties for the network
     */
    public LinkProperties getLinkProperties() {
        if(localLOGV) Slog.v(TAG, "EthernetStateTracker :: getLinkProperties" + mLinkProperties);
        return new LinkProperties(mLinkProperties); 
    }

    /**
     * A capability is an Integer/String pair, the capabilities
     * are defined in the class LinkSocket#Key.
     *
     * @return a copy of this connections capabilities, may be empty but never null.
     */
    public LinkCapabilities getLinkCapabilities() {
        if(localLOGV) Slog.v(TAG, "EthernetStateTracker :: getLinkCapabilities");
        return new LinkCapabilities();
    }

    /**
     * Check if default route is set
     */
    public boolean isDefaultRouteSet() {
        return mDefaultRouteSet.get();
    }

    /**
     * Set a flag indicating default route is set for the network
     */
    public void defaultRouteSet(boolean enabled) {
        mDefaultRouteSet.set(enabled);
    }

    /**
     * Captive Check is complete, switch to network
     */
    public void captivePortalCheckComplete() {
        //Not Implemented
    }
}
