/*
 * Copyright (C) 2010 The Android 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.
 */

package com.android.browser;

import com.android.browser.ScrollWebView.ScrollListener;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.PaintDrawable;
import android.view.ContextMenu;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.HashMap;
import java.util.Map;

/**
 * tabbed title bar for xlarge screen browser
 */
public class TabBar extends LinearLayout
        implements ScrollListener, OnClickListener {

    private static final int PROGRESS_MAX = 100;

    private Activity mActivity;
    private UiController mUiController;
    private TabControl mTabControl;
    private BaseUi mUi;

    private final int mTabWidthSelected;
    private final int mTabWidthUnselected;

    private TabScrollView mTabs;

    private ImageButton mNewTab;
    private int mButtonWidth;

    private Map<Tab, TabViewData> mTabMap;

    private boolean mUserRequestedUrlbar;
    private boolean mTitleVisible;
    private boolean mShowUrlMode;
    private boolean mHasReceivedTitle;

    private Drawable mGenericFavicon;
    private String mLoadingText;

    public TabBar(Activity activity, UiController controller, BaseUi ui) {
        super(activity);
        mActivity = activity;
        mUiController = controller;
        mTabControl = mUiController.getTabControl();
        mUi = ui;
        Resources res = activity.getResources();
        mTabWidthSelected = (int) res.getDimension(R.dimen.tab_width_selected);
        mTabWidthUnselected = (int) res.getDimension(R.dimen.tab_width_unselected);

        mTabMap = new HashMap<Tab, TabViewData>();
        Resources resources = activity.getResources();
        LayoutInflater factory = LayoutInflater.from(activity);
        factory.inflate(R.layout.tab_bar, this);
        mTabs = (TabScrollView) findViewById(R.id.tabs);
        mNewTab = (ImageButton) findViewById(R.id.newtab);
        mNewTab.setOnClickListener(this);
        mGenericFavicon = res.getDrawable(R.drawable.app_web_browser_sm);
        mLoadingText = res.getString(R.string.title_bar_loading);

        // TODO: Change enabled states based on whether you can go
        // back/forward.  Probably should be done inside onPageStarted.

        // build tabs
        int tabcount = mTabControl.getTabCount();
        for (int i = 0; i < tabcount; i++) {
            Tab tab = mTabControl.getTab(i);
            TabViewData data = buildTab(tab);
            TabView tv = buildView(data);
        }
        mTabs.setSelectedTab(mTabControl.getCurrentIndex());

        mUserRequestedUrlbar = false;
        mTitleVisible = true;
        mButtonWidth = -1;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (mButtonWidth == -1) {
            mButtonWidth = mNewTab.getMeasuredWidth();
        }
        int sw = mTabs.getMeasuredWidth();
        int w = right-left;
        if (w-sw < mButtonWidth) {
            sw = w - mButtonWidth;
        }
        mTabs.layout(0, 0, sw, bottom-top );
        mNewTab.layout(sw, 0, sw+mButtonWidth, bottom-top);
    }

    public void onClick(View view) {
        mUi.hideComboView();
        if (mNewTab == view) {
            mUiController.openTabToHomePage();
        } else if (mTabs.getSelectedTab() == view) {
            if (mUi.isFakeTitleBarShowing() && !isLoading()) {
                mUi.hideFakeTitleBar();
            } else {
                showUrlBar();
            }
        } else {
            int ix = mTabs.getChildIndex(view);
            if (ix >= 0) {
                mTabs.setSelectedTab(ix);
                mUiController.switchToTab(ix);
            }
        }
    }

    private void showUrlBar() {
        mUi.stopWebViewScrolling();
        mUi.showFakeTitleBar();
        mUserRequestedUrlbar = true;
    }

    private void setShowUrlMode(boolean showUrl) {
        mShowUrlMode = showUrl;
    }

    // callback after fake titlebar is shown
    void onShowTitleBar() {
        setShowUrlMode(false);
    }

    // callback after fake titlebar is hidden
    void onHideTitleBar() {
        setShowUrlMode(!mTitleVisible);
        Tab tab = mTabControl.getCurrentTab();
        tab.getWebView().requestFocus();
        mUserRequestedUrlbar = false;
    }

    // webview scroll listener

    @Override
    public void onScroll(boolean titleVisible) {
        // isLoading is using the current tab, which initially might not be set yet
        if (mTabControl.getCurrentTab() != null) {
            mTitleVisible = titleVisible;
            if (!mShowUrlMode && !mTitleVisible && !isLoading()) {
                if (mUserRequestedUrlbar) {
                    mUi.hideFakeTitleBar();
                } else {
                    setShowUrlMode(true);
                }
            } else if (mTitleVisible && !isLoading()) {
                if (mShowUrlMode) {
                    setShowUrlMode(false);
                }
            }
        }
    }

    @Override
    public void createContextMenu(ContextMenu menu) {
        MenuInflater inflater = mActivity.getMenuInflater();
        inflater.inflate(R.menu.title_context, menu);
        mActivity.onCreateContextMenu(menu, this, null);
    }

    private TabViewData buildTab(Tab tab) {
        TabViewData data = new TabViewData(tab);
        mTabMap.put(tab, data);
        return data;
    }

    private TabView buildView(final TabViewData data) {
        TabView tv = new TabView(mActivity, data);
        tv.setTag(data);
        tv.setOnClickListener(this);
        mTabs.addTab(tv);
        return tv;
    }

    /**
     * View used in the tab bar
     */
    class TabView extends LinearLayout implements OnClickListener {

        TabViewData mTabData;
        View mTabContent;
        TextView mTitle;
        View mIncognito;
        ImageView mIconView;
        ImageView mLock;
        ImageView mClose;
        boolean mSelected;
        boolean mInLoad;

        /**
         * @param context
         */
        public TabView(Context context, TabViewData tab) {
            super(context);
            mTabData = tab;
            setGravity(Gravity.CENTER_VERTICAL);
            setOrientation(LinearLayout.HORIZONTAL);
            setBackgroundResource(R.drawable.tab_background);
            LayoutInflater inflater = LayoutInflater.from(getContext());
            mTabContent = inflater.inflate(R.layout.tab_title, this, true);
            mTitle = (TextView) mTabContent.findViewById(R.id.title);
            mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
            mLock = (ImageView) mTabContent.findViewById(R.id.lock);
            mClose = (ImageView) mTabContent.findViewById(R.id.close);
            mClose.setOnClickListener(this);
            mIncognito = mTabContent.findViewById(R.id.incognito);
            mSelected = false;
            mInLoad = false;
            // update the status
            updateFromData();
        }

        @Override
        public void onClick(View v) {
            if (v == mClose) {
                closeTab();
            }
        }

        private void updateFromData() {
            mTabData.mTabView = this;
            if (mTabData.mUrl != null) {
                setDisplayTitle(mTabData.mUrl);
            }
            if (mTabData.mTitle != null) {
                setDisplayTitle(mTabData.mTitle);
            }
            setProgress(mTabData.mProgress);
            if (mTabData.mIcon != null) {
                setFavicon(mTabData.mIcon);
            }
            if (mTabData.mLock != null) {
                setLock(mTabData.mLock);
            }
            if (mTabData.mTab != null) {
                mIncognito.setVisibility(
                        mTabData.mTab.getWebView().isPrivateBrowsingEnabled() ?
                        View.VISIBLE : View.GONE);
            }
        }

        @Override
        public void setActivated(boolean selected) {
            mSelected = selected;
            mClose.setVisibility(mSelected ? View.VISIBLE : View.GONE);
            mTitle.setTextAppearance(mActivity, mSelected ?
                    R.style.TabTitleSelected : R.style.TabTitleUnselected);
            setHorizontalFadingEdgeEnabled(!mSelected);
            setFadingEdgeLength(50);
            super.setActivated(selected);
            setLayoutParams(new LayoutParams(selected ?
                    mTabWidthSelected : mTabWidthUnselected,
                    LayoutParams.MATCH_PARENT));
        }

        void setDisplayTitle(String title) {
            mTitle.setText(title);
        }

        void setFavicon(Drawable d) {
            mIconView.setImageDrawable(d);
        }

        void setLock(Drawable d) {
            if (null == d) {
                mLock.setVisibility(View.GONE);
            } else {
                mLock.setImageDrawable(d);
                mLock.setVisibility(View.VISIBLE);
            }
        }

        void setProgress(int newProgress) {
            if (newProgress >= PROGRESS_MAX) {
                mInLoad = false;
            } else {
                if (!mInLoad && getWindowToken() != null) {
                    mInLoad = true;
                }
            }
        }

        private void closeTab() {
            if (mTabData.mTab == mTabControl.getCurrentTab()) {
                mUiController.closeCurrentTab();
            } else {
                mUiController.closeTab(mTabData.mTab);
            }
        }

    }

    /**
     * Store tab state within the title bar
     */
    class TabViewData {

        Tab mTab;
        TabView mTabView;
        int mProgress;
        Drawable mIcon;
        Drawable mLock;
        String mTitle;
        String mUrl;

        TabViewData(Tab tab) {
            mTab = tab;
            WebView web = tab.getWebView();
            if (web != null) {
                setUrlAndTitle(web.getUrl(), web.getTitle());
            }
        }

        void setUrlAndTitle(String url, String title) {
            mUrl = url;
            mTitle = title;
            if (mTabView != null) {
                if (title != null) {
                    mTabView.setDisplayTitle(title);
                } else if (url != null) {
                    mTabView.setDisplayTitle(UrlUtils.stripUrl(url));
                }
            }
        }

        void setProgress(int newProgress) {
            mProgress = newProgress;
            if (mTabView != null) {
                mTabView.setProgress(mProgress);
            }
        }

        void setFavicon(Bitmap icon) {
            Drawable[] array = new Drawable[3];
            array[0] = new PaintDrawable(Color.BLACK);
            array[1] = new PaintDrawable(Color.WHITE);
            if (icon == null) {
                array[2] = mGenericFavicon;
            } else {
                array[2] = new BitmapDrawable(icon);
            }
            LayerDrawable d = new LayerDrawable(array);
            d.setLayerInset(1, 1, 1, 1, 1);
            d.setLayerInset(2, 2, 2, 2, 2);
            mIcon = d;
            if (mTabView != null) {
                mTabView.setFavicon(mIcon);
            }
        }

    }

    // TabChangeListener implementation

    public void onSetActiveTab(Tab tab) {
        mTabs.setSelectedTab(mTabControl.getTabIndex(tab));
        TabViewData tvd = mTabMap.get(tab);
        if (tvd != null) {
            tvd.setProgress(tvd.mProgress);
            // update the scroll state
            WebView webview = tab.getWebView();
            onScroll(webview.getVisibleTitleHeight() > 0);
        }
    }

    public void onFavicon(Tab tab, Bitmap favicon) {
        TabViewData tvd = mTabMap.get(tab);
        if (tvd != null) {
            tvd.setFavicon(favicon);
        }
    }

    public void onNewTab(Tab tab) {
        TabViewData tvd = buildTab(tab);
        buildView(tvd);
    }

    public void onProgress(Tab tab, int progress) {
        TabViewData tvd = mTabMap.get(tab);
        if (tvd != null) {
            tvd.setProgress(progress);
        }
    }

    public void onRemoveTab(Tab tab) {
        TabViewData tvd = mTabMap.get(tab);
        if (tvd != null) {
            TabView tv = tvd.mTabView;
            if (tv != null) {
                mTabs.removeTab(tv);
            }
        }
        mTabMap.remove(tab);
    }

    public void onUrlAndTitle(Tab tab, String url, String title) {
        mHasReceivedTitle = true;
        TabViewData tvd = mTabMap.get(tab);
        if (tvd != null) {
            tvd.setUrlAndTitle(url, title);
        }
    }

    public void onPageFinished(Tab tab) {
        if (!mHasReceivedTitle) {
            TabViewData tvd = mTabMap.get(tab);
            if (tvd != null) {
                tvd.setUrlAndTitle(tvd.mUrl, null);
            }
        }
    }

    public void onPageStarted(Tab tab, String url, Bitmap favicon) {
        mHasReceivedTitle = false;
        TabViewData tvd = mTabMap.get(tab);
        if (tvd != null) {
            tvd.setUrlAndTitle(url, null);
            tvd.setFavicon(favicon);
            tvd.setUrlAndTitle(url, mLoadingText);
        }
    }

    private boolean isLoading() {
        TabViewData tvd = mTabMap.get(mTabControl.getCurrentTab());
        if ((tvd != null) && (tvd.mTabView != null)) {
            return tvd.mTabView.mInLoad;
        } else {
            return false;
        }
    }

}