/*
 * Copyright (C) Azureus Software, Inc, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details ( see the LICENSE file ).
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package com.aelitis.azureus.ui.swt.mdi;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.ui.swt.Utils;
import org.gudy.azureus2.ui.swt.mainwindow.SWTThread;
import org.gudy.azureus2.ui.swt.plugins.UISWTView;
import org.gudy.azureus2.ui.swt.pluginsimpl.UISWTViewCore;

import com.aelitis.azureus.ui.common.viewtitleinfo.ViewTitleInfo;
import com.aelitis.azureus.ui.mdi.MdiEntryVitalityImage;
import com.aelitis.azureus.ui.swt.skin.SWTSkin;
import com.aelitis.azureus.ui.swt.skin.SWTSkinObject;
import com.aelitis.azureus.ui.swt.skin.SWTSkinObjectContainer;

public class TabbedEntry
	extends BaseMdiEntry implements DisposeListener
{
	private CTabItem swtItem;

	private SWTSkin skin;

	private boolean showonSWTItemSet;

	private boolean buildonSWTItemSet;

	private static long uniqueNumber = 0;

	public TabbedEntry(TabbedMDI mdi, SWTSkin skin, String id) {
		super(mdi, id);
		this.skin = skin;
	}

	/* (non-Javadoc)
	 * @note SideBarEntrySWT is neary identical to this one.  Please keep them
	 *       in sync until commonalities are placed in BaseMdiEntry
	 */
	public void build() {
		Utils.execSWTThread(new AERunnable() {
			public void runSupport() {
				swt_build();
				TabbedEntry.super.build();
			}
		});
	}
	
	public boolean swt_build() {
		if (swtItem == null) {
			buildonSWTItemSet = true;
			return true;
		}
		buildonSWTItemSet = false;

		Control control = swtItem.getControl();
		if (control == null) {
			Composite parent = swtItem.getParent();
			SWTSkinObject soParent = (SWTSkinObject) parent.getData("SkinObject");

			String skinRef = getSkinRef();
			if (skinRef != null) {
				Shell shell = parent.getShell();
				Cursor cursor = shell.getCursor();
				try {
					shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));

//					SWTSkinObjectContainer soContents = (SWTSkinObjectContainer) skin.createSkinObject(
//							"MdiContents." + uniqueNumber++, "mdi.content.item",
//							soParent, getSkinRefParams());
//					skin.addSkinObject(soContents);

					
					SWTSkinObject skinObject = skin.createSkinObject(id, skinRef,
							soParent, getDatasourceCore());
					
					control = skinObject.getControl();
					control.setLayoutData(Utils.getFilledFormData());
					control.getParent().layout(true);
					// swtItem.setControl will set the control's visibility based on
					// whether the control is selected.  To ensure it doesn't set
					// our control invisible, set selection now
					CTabItem oldSelection = swtItem.getParent().getSelection();
					swtItem.getParent().setSelection(swtItem);
					swtItem.setControl(control);
					if (oldSelection != null) {
						swtItem.getParent().setSelection(oldSelection);
					}
					setSkinObject(skinObject, skinObject);
				} finally {
					shell.setCursor(cursor);
				}
			} else if (view != null) {
				try {
					SWTSkinObjectContainer soContents = (SWTSkinObjectContainer) skin.createSkinObject(
							"MdiIView." + uniqueNumber++, "mdi.content.item",
							soParent);

					parent.setBackgroundMode(SWT.INHERIT_NONE);

					Composite viewComposite = soContents.getComposite();
					//viewComposite.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
					//viewComposite.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND));

					boolean doGridLayout = true;
					UISWTView swtView = view;
					if (swtView.getControlType() == UISWTViewCore.CONTROLTYPE_SKINOBJECT) {
						doGridLayout = false;
					}
					if (doGridLayout) {
  					GridLayout gridLayout = new GridLayout();
  					gridLayout.horizontalSpacing = gridLayout.verticalSpacing = gridLayout.marginHeight = gridLayout.marginWidth = 0;
  					viewComposite.setLayout(gridLayout);
  					viewComposite.setLayoutData(Utils.getFilledFormData());
					}

					UISWTViewCore uiViewCore = view;
					uiViewCore.setSkinObject(soContents, soContents.getComposite());

					view.initialize(viewComposite);
					setTitle(view.getFullTitle());

					Composite iviewComposite = view.getComposite();
					control = iviewComposite;
					if (doGridLayout) {
						Object existingLayoutData = iviewComposite.getLayoutData();
						Object existingParentLayoutData = iviewComposite.getParent().getLayoutData();
						if (existingLayoutData == null
								|| !(existingLayoutData instanceof GridData)
								&& (existingParentLayoutData instanceof GridLayout)) {
							GridData gridData = new GridData(GridData.FILL_BOTH);
							iviewComposite.setLayoutData(gridData);
						}
					}

					//soContents is invisible, so of course iviwComposite is invisible
					//We should do the one time layout on the first show..
					//if (iviewComposite.isVisible()) {
					//	parent.layout(true, true);
					//}

					CTabItem oldSelection = swtItem.getParent().getSelection();
					swtItem.getParent().setSelection(swtItem);
					swtItem.setControl(soContents.getControl());
					if (oldSelection != null) {
						swtItem.getParent().setSelection(oldSelection);
					}
					setSkinObject(soContents, soContents);
				} catch (Exception e) {
					Debug.out("Error creating sidebar content area for " + id, e);
					close(true);
				}

			} else if (viewClass != null) {
				try {
					UISWTViewCore view = (UISWTViewCore) viewClass.newInstance();

					if (view != null) {
						setCoreView(view);
						// now that we have an view, go through show one more time
						return swt_build();
					}
					close(true);
					return false;
				} catch (Exception e) {
					Debug.out(e);
					close(true);
				}
			}

			if (control != null && !control.isDisposed()) {
				control.setData("BaseMDIEntry", this);
				control.addDisposeListener(new DisposeListener() {
					public void widgetDisposed(DisposeEvent e) {
						close(true);
					}
				});
			} else {
				return false;
			}
		}
		return true;
	}

	/* (non-Javadoc)
	 * @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#show()
	 */
	public void show() {
		// ensure show order by user execThreadLater
		// fixes case where two showEntries are called, the first from a non
		// SWT thread, and the 2nd from a SWT thread.  The first one will run last
		// showing itself
		Utils.execSWTThreadLater(0, new AERunnable() {
			public void runSupport() {
				swt_show();
			}
		});
	}

	private void swt_show() {
		if (swtItem == null) {
			showonSWTItemSet = true;
			return;
		}
		showonSWTItemSet = false;
		if (!swt_build()) {
			return;
		}
		
		triggerOpenListeners();


		if (swtItem.getParent().getSelection() != swtItem) {
			swtItem.getParent().setSelection(swtItem);
		}

		super.show();
	}

	/**
	 * Tabs don't have Vitality Image support (yet)
	 */
	public MdiEntryVitalityImage addVitalityImage(String imageID) {
		return null; // new SideBarVitalityImageSWT(this, imageID);
	}

	/* (non-Javadoc)
	 * @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#isCloseable()
	 */
	public boolean isCloseable() {
		// override.. we don't support non-closeable
		return true;
	}

	public void setSwtItem(CTabItem swtItem) {
		this.swtItem = swtItem;
		if (swtItem == null) {
			setDisposed(true);
			return;
		}
		setDisposed(false);

		swtItem.addDisposeListener(this);
		String title = getTitle();
		if (title != null) {
			swtItem.setText(escapeAccelerators(title));
		} else if (viewClass != null) {
			swtItem.setText(viewClass.getSimpleName());
		}
		if (buildonSWTItemSet) {
			build();
		}
		if (showonSWTItemSet) {
			show();
		}
	}

	public Item getSwtItem() {
		return swtItem;
	}

	/* (non-Javadoc)
	 * @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#setTitle(java.lang.String)
	 */
	public void setTitle(String title) {
		super.setTitle(title);

		if (swtItem != null) {
			swtItem.setText(escapeAccelerators(title));
		}
	}

	/* (non-Javadoc)
	 * @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#getVitalityImages()
	 */
	public MdiEntryVitalityImage[] getVitalityImages() {
		return new MdiEntryVitalityImage[0];
	}

	/* (non-Javadoc)
	 * @see com.aelitis.azureus.ui.swt.mdi.BaseMdiEntry#close()
	 */
	public boolean close(boolean forceClose) {
    // triggerCloseListener
		if (!super.close(forceClose)) {
			return false;
		}

		Utils.execSWTThread(new Runnable() {
			public void run() {
				if (swtItem != null && !swtItem.isDisposed()) {
					swtItem.dispose();
					swtItem = null;
				} else if (view != null) {
					setCoreView(null);

					triggerCloseListeners(!SWTThread.getInstance().isTerminated());
				}
			}
		});
		return true;
	}

	public void redraw() {
	}

	public void widgetDisposed(DisposeEvent e) {
		setSwtItem(null);

		triggerCloseListeners(!SWTThread.getInstance().isTerminated());

		UISWTViewCore view = getCoreView();
		if (view != null) {
			setCoreView(null);
		}
		SWTSkinObject so = getSkinObject();
		if (so != null) {
			setSkinObject(null, null);
			so.getSkin().removeSkinObject(so);
		}
		
		// delay saving of removing of auto-open flag.  If after the delay, we are 
		// still alive, it's assumed the user invoked the close, and we should
		// remove the auto-open flag
		Utils.execSWTThreadLater(0, new AERunnable() {
			public void runSupport() {
				// even though execThreadLater will not run on close of app because
				// the display is disposed, do a double check of tree disposal just
				// in case.  We don't want to trigger close listeners or
				// remove autoopen parameters if the user is closing the app (as
				// opposed to closing  the sidebar)
				if (SWTThread.getInstance().isTerminated()) {
					return;
				}

				try {
					COConfigurationManager.removeParameter("SideBar.AutoOpen." + id);
				} catch (Exception e2) {
					Debug.out(e2);
				}

				mdi.removeItem(TabbedEntry.this);
				mdi.removeEntryAutoOpen(id);
			}
		});
	}

	private String escapeAccelerators(String str) {
		if (str == null) {
			return (str);
		}

		return str.replaceAll("&", "&&");
	}
	
	public void expandTo() {
	}
	
	public void viewTitleInfoRefresh(ViewTitleInfo titleInfoToRefresh) {
		super.viewTitleInfoRefresh(titleInfoToRefresh);

		if (titleInfoToRefresh == null || this.viewTitleInfo != titleInfoToRefresh) {
			return;
		}
		if (isDisposed()) {
			return;
		}

		String textIndicator = null;
		try {
			textIndicator = (String) viewTitleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_INDICATOR_TEXT);
		} catch (Exception e) {
			Debug.out(e);
		}
		if (textIndicator != null) {
			setPullTitleFromView(false);
		}
		
		String newText = (String) viewTitleInfo.getTitleInfoProperty(ViewTitleInfo.TITLE_TEXT);
		if (newText != null) {
			if (textIndicator != null) {
				newText += " (" + textIndicator + ")";
			}
			setPullTitleFromView(false);
			setTitle(newText);
		} else if (view != null) {
			newText = view.getFullTitle();
			if (textIndicator != null) {
				newText += " (" + textIndicator + ")";
			}
			setTitle(newText);
		}
	}
	
	// @see com.aelitis.azureus.ui.mdi.MdiEntry#isSelectable()
	public boolean isSelectable() {
		return true;
	}

	// @see com.aelitis.azureus.ui.mdi.MdiEntry#setSelectable(boolean)
	public void setSelectable(boolean selectable) {
	}

	// @see com.aelitis.azureus.ui.swt.mdi.MdiEntrySWT#addListener(com.aelitis.azureus.ui.swt.mdi.MdiSWTMenuHackListener)
	public void addListener(MdiSWTMenuHackListener l) {
		// TODO Auto-generated method stub
	}

	// @see com.aelitis.azureus.ui.swt.mdi.MdiEntrySWT#removeListener(com.aelitis.azureus.ui.swt.mdi.MdiSWTMenuHackListener)
	public void removeListener(MdiSWTMenuHackListener l) {
		// TODO Auto-generated method stub
	}
}
