/*
 * 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.regex.Matcher;

import android.net.NetworkInfo;
import android.util.Config;
import android.util.Slog;
import java.util.StringTokenizer;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import com.maxwell.net.ethernet.IEthernetManager;
import com.maxwell.net.ethernet.EthernetManager;
import android.os.UserHandle;
import android.content.BroadcastReceiver;

/**
 * Listens for events from kernel, and passes them on
 * to the {@link EtherentStateTracker} for handling. Runs in its own thread.
 *
 * @hide
 */
public class EthernetMonitor {
    private static final String TAG = "EthernetMonitor";
    /*Events Broradcast to update link status*/
    private static final int CONNECTED = 1;
    private static final int DISCONNECTED = 2;
    private static final int PHYUP = 3;
    private static final int FAILED = -1;
    private static final int STOPPED = 0;
    private static final int RUNNING = 1;
    private static int mStatus = STOPPED;


    /*Events received from Kernel on link concet/disconnect*/
    private static final int ADD_ADDR = 20;
    private static final int NEW_LINK = 16;
    private static final int DEL_LINK = 17;
    private static final boolean localLOGV = false;
    private Context mContext = null;
    private BroadcastReceiver mBootCompletedReceiver;
    private boolean isBooted = false;

    public EthernetMonitor(Context context) {
        mContext = context;

        /*Register receiver for listening boot completed receiver*/
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
	mBootCompletedReceiver = new BootCompletedReceiver();
	mContext.registerReceiver(mBootCompletedReceiver, filter);
    }

    public synchronized void startMonitoring() {
        if (mStatus == STOPPED){
            new MonitorThread().start();
        }
    }

    public synchronized void pauseMonitoring() {
        mStatus = STOPPED;
    }

    class MonitorThread extends Thread {
        public MonitorThread() {
            super("EthMonitor");
        }

        public void run() {
            //noinspection InfiniteLoopStatement
            mStatus = RUNNING;

            for (;;) {
                int index;
                int i;
                int cmd;
                String dev;

                if (localLOGV) Slog.v(TAG, "go poll events");

                String eventName = EthernetNative.waitForEvent();
                if (mStatus != RUNNING) {
                    break;
                }
                if (eventName == null) {
                    continue;
                }

                if (localLOGV) Slog.v(TAG, "get event " + eventName);

                /*
                 * Map event name into event enum
                 */
                i = 0;
                while (i < eventName.length()) {
                    index = eventName.substring(i).indexOf(":");
                    if (index == -1)
                        break;
                    dev = eventName.substring(i, index);
                    i += index + 1;
                    index = eventName.substring(i).indexOf(":");
                    if (index == -1)
                        break;
                    cmd = Integer.parseInt(eventName.substring(i, i+index));
                    i += index + 1;
                    if (localLOGV) Slog.v(TAG, "dev: " + dev + " ev " + cmd);
                    switch (cmd) {
                        case DEL_LINK:
                            handleEvent(dev, DISCONNECTED);
                            break;
                        case ADD_ADDR:
                            handleEvent(dev, CONNECTED);
                            break;
                        case NEW_LINK:
                            handleEvent(dev, PHYUP);
                            break;
                    }
                }
            }
            if (localLOGV) Slog.v(TAG, "run<<< Exiting Monitor Thread");
        }

        /**
         * Brocast receiver to notify service about link status change events
         */
        public void sendMonitorResullt(String ifname, int event){
            Intent intent = new Intent();
            Slog.v(TAG, "sendMonitorResult:: isBooted " + isBooted);
            if(!isBooted) { //MAX-3975 : Added check to send broadcast before boot completed event is sent
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
            }
	    intent.setAction(EthernetManager.ETHERNET_MONITOR_RESULT);
	    intent.putExtra("InterfaceName", ifname);
	    intent.putExtra("EventName", event);
	    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
        }

        /**
         * Handle all supplicant events except STATE-CHANGE
         * @param event the event type
         * @param remainder the rest of the string following the
         * event name and &quot;&#8195;&#8212;&#8195;&quot;
         */
        void handleEvent(String ifname,int event) {
            switch (event) {
                case DISCONNECTED:
                    sendMonitorResullt(ifname, DISCONNECTED);
                    break;
                case CONNECTED:
                    sendMonitorResullt(ifname, CONNECTED);
                    break;
                case PHYUP:
                    sendMonitorResullt(ifname, PHYUP);
                    break;
                default:
                    sendMonitorResullt(ifname, FAILED);
                    break;
            }
        }
    }

    //Receiver for getting boot completed receiver
    private class BootCompletedReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent != null){
                if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
                    Slog.d(TAG, "Boot completed event is received:: isBooted " + isBooted);
                    isBooted = true;
                }
            }
        }
   }
}
