/*
 * blanco Framework
 * Copyright (C) 2004-2006 IGA Tosiki
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.plugin.filemanager.views;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.DrillDownAdapter;
import org.eclipse.ui.part.ViewPart;

import blanco.plugin.filemanager.BlancoFileManager;

/**
 * ディレクトリビューを実現します。
 * 
 * @author IGA Tosiki
 */
public class BlancoFileManagerDirectoryView extends ViewPart {
    private TreeViewer fTreeViewer;

    private DrillDownAdapter fDrillDownAdapter;

    /**
     * ディレクトリのみ表示と ディレクトリとファイルを表示とを切り替えます。
     */
    private Action fActionDirectoryOnlyOrDirectoryFile;

    /**
     * 更新ボタン。
     */
    private Action fActionRefresh;

    private Action fDoubleClickAction;

    class NameSorter extends ViewerSorter {
    }

    /**
     * The constructor.
     */
    public BlancoFileManagerDirectoryView() {
    }

    /**
     * This is a callback that will allow us to create the viewer and initialize
     * it.
     */
    public synchronized void createPartControl(Composite parent) {
        fTreeViewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
                | SWT.V_SCROLL);
        fDrillDownAdapter = new DrillDownAdapter(fTreeViewer);
        fTreeViewer.setContentProvider(new BlancoFileManagerProvider());
        fTreeViewer.setLabelProvider(new BlancoFileManagerLabelProvider());
        fTreeViewer.setSorter(new NameSorter());
        fTreeViewer.setInput(getViewSite());
        fTreeViewer
                .addSelectionChangedListener(new ISelectionChangedListener() {
                    public void selectionChanged(
                            final SelectionChangedEvent event) {
                        System.out.println(event.toString());
                        // TODO このタイミングでためしにテーブルView連動を実装してみたところ、操作感が非常に悪い。
                        // new
                        // BlancoFileManagerTreeSelectionChangedAction(fTreeViewer)
                        // .processSelection((ITreeSelection) event
                        // .getSelection());
                    }
                });
        makeActions();
        hookContextMenu();
        hookDoubleClickAction();
        contributeToActionBars();

        BlancoFileManager.getInstance().setDirectoryView(this);
    }

    private void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu");
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                BlancoFileManagerDirectoryView.this.fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(fTreeViewer.getControl());
        fTreeViewer.getControl().setMenu(menu);
        getSite().registerContextMenu(menuMgr, fTreeViewer);
    }

    private void contributeToActionBars() {
        IActionBars bars = getViewSite().getActionBars();
        fillLocalPullDown(bars.getMenuManager());
        fillLocalToolBar(bars.getToolBarManager());
    }

    private void fillLocalPullDown(IMenuManager manager) {
        manager.add(fActionDirectoryOnlyOrDirectoryFile);
        manager.add(new Separator());
        manager.add(fActionRefresh);
    }

    private void fillContextMenu(IMenuManager manager) {
        manager.add(fActionDirectoryOnlyOrDirectoryFile);
        manager.add(fActionRefresh);
        manager.add(new Separator());
        fDrillDownAdapter.addNavigationActions(manager);
        // Other plug-ins can contribute there actions here
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
    }

    private void fillLocalToolBar(IToolBarManager manager) {
        manager.add(fActionDirectoryOnlyOrDirectoryFile);
        manager.add(fActionRefresh);
        manager.add(new Separator());
        fDrillDownAdapter.addNavigationActions(manager);
    }

    private void makeActions() {
        // ディレクトリのみ、とディレクトリ＋ファイルの表示切替をします。
        fActionDirectoryOnlyOrDirectoryFile = new Action() {
            public void run() {
                final BlancoFileManagerProvider provider = (BlancoFileManagerProvider) fTreeViewer
                        .getContentProvider();
                // モードを反転します。
                provider.setIsProcessFile(!provider.getIsProcessFile());

                String objectName = ISharedImages.IMG_OBJ_FILE;
                if (provider.getIsProcessFile()) {
                    objectName = ISharedImages.IMG_OBJ_FILE;
                } else {
                    objectName = ISharedImages.IMG_OBJ_FOLDER;
                }
                fActionDirectoryOnlyOrDirectoryFile
                        .setImageDescriptor(PlatformUI.getWorkbench()
                                .getSharedImages().getImageDescriptor(
                                        objectName));

                // 再表示
                refreshTree();
            }
        };
        fActionDirectoryOnlyOrDirectoryFile.setText("Mode");
        fActionDirectoryOnlyOrDirectoryFile
                .setToolTipText("change directory view mode.");
        fActionDirectoryOnlyOrDirectoryFile.setImageDescriptor(PlatformUI
                .getWorkbench().getSharedImages().getImageDescriptor(
                        ISharedImages.IMG_OBJ_FILE));

        fActionRefresh = new Action() {
            public void run() {
                // 再表示
                refreshTree();
            }
        };
        fActionRefresh.setText("Refresh");
        fActionRefresh.setToolTipText("Refresh");
        fActionRefresh.setImageDescriptor(PlatformUI.getWorkbench()
                .getSharedImages().getImageDescriptor(
                        ISharedImages.IMG_DEF_VIEW));

        fDoubleClickAction = new BlancoFileManagerTreeSelectionDoubleClickAction(
                fTreeViewer);
    }

    private void hookDoubleClickAction() {
        fTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
            public void doubleClick(DoubleClickEvent event) {
                fDoubleClickAction.run();
            }
        });
    }

    /**
     * Passing the focus request to the viewer's control.
     */
    public void setFocus() {
        fTreeViewer.getControl().setFocus();
    }

    /**
     * 全般的な再表示を処理します。
     */
    private void refreshTree() {
        try {
            // ちらつき防止のため再描画を抑制。
            fTreeViewer.getTree().setRedraw(false);

            final ITreeSelection treeSelection = (ITreeSelection) fTreeViewer
                    .getSelection();
            final TreePath[] currentTreePaths = treeSelection.getPaths();
            if (currentTreePaths != null && currentTreePaths.length > 0) {

                for (int index = 0; index < currentTreePaths[0]
                        .getSegmentCount(); index++) {
                    fTreeViewer.refresh(currentTreePaths[0].getSegment(index));
                }

                // ツリーの終端について、Expandを試みます。
                fTreeViewer.setExpandedState(currentTreePaths[0]
                        .getLastSegment(), true);
            } else {
                // カレントが判定できない場合には、ルートから根こそぎリフレッシュします。
                fTreeViewer.refresh();
            }

        } finally {
            // 再描画抑制を解除。
            fTreeViewer.getTree().setRedraw(true);
        }

        // 現在の選択ポイントが表示されるようにする。
        fTreeViewer.setSelection(fTreeViewer.getSelection(), true);
    }
}