/**
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * Copyright © 2009 Mindoo GmbH
 *
 * @author Tammo Riedinger
 *
 */
package com.mindoo.ec09.framework.application;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ContainerAdapter;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import javax.swing.JComponent;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.mindoo.ec09.framework.views.View;
import com.mindoo.ec09.framework.views.ViewActivationListener;
import com.mindoo.ec09.framework.views.ViewManager;


public abstract class MultiViewApplication extends MultiTabsApplication implements ViewManager {
	@Override
	protected Container createContentPane() {
		JTabbedPane pane=new JTabbedPane();
		
		pane.addChangeListener(m_tabsChangeListener);
		pane.addContainerListener(m_tabsRemovedListener);
		
		return pane;
	}
    
	protected void configureInternalContentPane(Object userObject, Container contentPane) {
		if (userObject instanceof View) {
			contentPane.setLayout(new BorderLayout());
			contentPane.add(((View)userObject).createComponent(),BorderLayout.CENTER);
		}
		else
			super.configureInternalContentPane(userObject,contentPane);
	}

    private ArrayList<ViewActivationListener> m_viewListeners=new ArrayList<ViewActivationListener>();
    private HashMap<JComponent,View> m_views=new LinkedHashMap<JComponent,View>();

	private View m_formerActiveView=null;
	private ContainerListener m_tabsRemovedListener=new ContainerAdapter() {
		@Override
		public void componentRemoved(ContainerEvent evt) {
			if (getTabCount()==0 && m_formerActiveView!=null) {
				for (ViewActivationListener l:getViewActivationListeners()) 
					l.activationChanged(null, m_formerActiveView);
			}
			
			JComponent tab=(JComponent)evt.getChild();
			unRegisterView(tab,getView(tab));
		}
    };
    private ChangeListener m_tabsChangeListener=new ChangeListener() {
		public void stateChanged(ChangeEvent evt) {
			View newView=null;
			
			JComponent tab=getSelectedTab();
			if (tab!=null) {
				newView=getView(getSelectedTab());
				
				if (newView!=null && !newView.equals(m_formerActiveView)) {
					newView.setFocus();
					
					for (ViewActivationListener l:getViewActivationListeners())
						l.activationChanged(newView, m_formerActiveView);
				}
				m_formerActiveView=newView;
			}
		}
	};
	
	private void registerView(JComponent tab, View view) {
		m_views.put(tab,view);
	}
	
	private void unRegisterView(JComponent tab, View view) {
		m_views.remove(tab);
	}
	
	private View getView(JComponent tab) {
		return m_views.get(tab);
	}
	
	private JComponent findTab(View view) {
		for (JComponent tab:getAllInternalTabs()) {
			View v=getView(tab);
			
			if (v!=null && v.equals(view))
				return tab;
		}
		return null;
	}
	
	public void addView(View view) {
		JComponent tab=addNewTab(view.getTitle(), view, false);
		
		registerView(tab,view);
		
		setActiveView(view);
	}
	
	public void addViewAt(int index, View view) {
		JComponent tab=addNewTabAt(index, view.getTitle(), view, false);
		
		registerView(tab,view);
		
		setActiveView(view);
	}
	
	public void setViewAt(int index, View view) {
		if (index<0)
			throw new IllegalArgumentException("MultiViewApplication: Specified index is out of range!");

		if (index>=getTabCount()) {
			addView(view);
			return;
		}
		
		View oldView=getViewAt(index);
		
		if (oldView!=view) {
			removeTabAt(index);
			
			addViewAt(index, view);
		}
		else {
			setTitleAt(index, view.getTitle());
			
			setActiveView(view);
		}
	}
	
	public int indexOfView(View view) {
		JComponent[] tabs=getAllInternalTabs();
		for (int i=0; i<tabs.length; i++) {
			View v=getView(tabs[i]);
			
			if (v!=null && v.equals(view))
				return i;
		}
		return -1;
	}
	
	public View getViewAt(int index) {
		return getView(getTabAt(index));
	}

	public void addViewActivationListener(ViewActivationListener listener) {
		if (!m_viewListeners.contains(listener))
			m_viewListeners.add(listener);
	}
	
	public void removeViewActivationListener(ViewActivationListener listener) {
		m_viewListeners.remove(listener);
	}
	
	private ViewActivationListener[] getViewActivationListeners() {
		return m_viewListeners.toArray(new ViewActivationListener[0]);
	}
	
	public View getActiveView() {
		return getView(getSelectedTab());
	}

	public Iterator<View> getViews() {
		return m_views.values().iterator();
	}
	
	public View findView(String id) {
		Iterator<View> views=getViews();
		while (views.hasNext()) {
			View v=views.next();
			
			if (id.equals(v.getID()))
				return v;
		}
		return null;
	}

	public void removeView(View view) {
		JComponent tab=findTab(view);
		if (tab!=null)
			removeTab(tab);
	}

	public void setActiveView(View view) {
		JComponent tab=findTab(view);
		if (tab!=null) {
			setSelectedTab(tab);
			
			if (getTabCount()==1)
				m_tabsChangeListener.stateChanged(null);
		}
	}
}