/**
 * File:    CustomPropertyDescriptor.java
 * Created: 17.12.2006
 *
/*******************************************************************************
 * Copyright (c) 2007-2009 Open Wide SA, France <www.openwide.fr>
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Marc Dutoo, Open Wide SA 
 *    	- initial API and implementation
 *******************************************************************************/

package org.eclipse.jwt.we.conf.property.edit.properties;

import java.util.Arrays;
import java.util.List;

import org.eclipse.emf.common.ui.celleditor.ExtendedComboBoxCellEditor;
import org.eclipse.emf.common.ui.celleditor.ExtendedDialogCellEditor;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.emf.edit.ui.provider.PropertyDescriptor;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jwt.we.conf.model.Aspect;
import org.eclipse.jwt.we.conf.model.aspects.AspectManager;
import org.eclipse.jwt.we.conf.property.model.aspects.PropertyAspectFactory;
import org.eclipse.jwt.we.conf.property.model.property.Property;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;


/**
 * This PropertyDescriptor allows to display and edit the "value" attribute
 * of dynamic properties (conf-model Property) in the PropertyPage according to the EDataType specified in a
 * Property's Aspect definition, rather than in its EMF model (which is EString).
 * 
 * In order to use it, it must be created in a customized AdapterFactoryContentProvider's
 * createPropertySource() method, or registered in a pluggable one;
 * 
 * @version $Id: PropertyPropertyDescriptor.java,v 1.1 2010-05-10 10:04:30 chsaad Exp $
 * @author Marc Dutoo, Open Wide SA
 * @since 0.6
 */
public class PropertyPropertyDescriptor
		extends PropertyDescriptor
{

	/**
	 * The constructor.
	 * 
	 * @param object
	 *            The object.
	 * @param itemPropertyDescriptor
	 *            The itemPropertyDescriptor.
	 */
	public PropertyPropertyDescriptor(Object object,
			IItemPropertyDescriptor itemPropertyDescriptor)
	{
		super(object, itemPropertyDescriptor);
	}

	
	/**
	 * Returns a customized label provider that displays
	 * the Property value according to its Aspect-defined
	 * type.
	 */
  public ILabelProvider getLabelProvider() 
  {
    final IItemLabelProvider itemLabelProvider = itemPropertyDescriptor.getLabelProvider(object);
    return 
      new LabelProvider()
      {
        @Override
        public String getText(Object value)
        {
        	// NB. it has been tested in CustomAdapterFactoryContentProvider
        	// that this is the "value" EAttribute of a Property object
    	    Property propertyObject = (Property) object;
    		Aspect propertyAspect = AspectManager.INSTANCE.getAspect(propertyObject);
    		if (propertyAspect == null) {
    		    // not corresponding Aspect definition available for property TODO log
    		    return null;
    		}
    		
            EClassifier propertyETypeClassifier = propertyAspect.getAspectInstanceEType();
    	    if (!(propertyETypeClassifier instanceof EDataType))
    	    {
    	      // not a DataType (should not happen TODO log)
    	      return null;
    	    }
            EDataType eDataType = (EDataType) propertyETypeClassifier;
      	    // TODO case of localized boolean, case of null
            if (value != null && !eDataType.isInstance(value))
            {
          	    // case when a Property's instance type has been changed in the ConfModel :
        	    // let's recreate a new default value for the new instance type
            	Object oldValue = value;
            	value = PropertyAspectFactory.INSTANCE.createDefaultValue(eDataType, propertyAspect.getDefaultValue()); // TODO better than new
            	if (oldValue.equals(propertyObject.getValue())) {
	            	// MDU TODO should be done in model, ex in Property.getValue()
	            	// NB. value != propertyObject.getValue() happens when trying to display
	            	// choosable values in combobox, ex. for Boolean
	            	propertyObject.setValue(value);
            	}
            }

          // now it the propertyValue has the right type, let's display it
          return EcoreUtil.convertToString(eDataType, value);

          // NB. default behaviour is useless, because it displays an
          // editor for java Objects
          //return itemLabelProvider.getText(object);
        }
        @Override
        public Image getImage(Object object)
        {
          // default behaviour
          return ExtendedImageRegistry.getInstance().getImage(itemLabelProvider.getImage(object));
        }
      };
  }

	/**
	 * inspired from PropertyDescriptor.createPropertyEditor() case dataType
	 * 
	 * @param composite
	 *            The composite.
	 * @return the cell editor
	 */
	@Override
	public CellEditor createPropertyEditor(Composite parent)
	{
	    CellEditor result = null;
	    
    	// NB. it has been tested in CustomAdapterFactoryContentProvider
    	// that this is the "value" EAttribute of a Property object
	    Property propertyObject = (Property) object;
		Aspect propertyAspect = AspectManager.INSTANCE.getAspect(propertyObject);
		if (propertyAspect == null) {
		    // not corresponding Aspect definition available for property TODO log
		    return null;
		}
		
        EClassifier propertyETypeClassifier = propertyAspect.getAspectInstanceEType();
	    if (!(propertyETypeClassifier instanceof EDataType))
	    {
	      // not a DataType (should not happen TODO log)
	      return null;
	    }
        final EDataType eDataType = (EDataType) propertyETypeClassifier;
        if (eDataType.isSerializable())
        {
          if (itemPropertyDescriptor.isMany(object))
          {
        	// MDU TODO let Property be many and adapt this
            final ILabelProvider editLabelProvider = getEditLabelProvider();
            result = 
              new ExtendedDialogCellEditor(parent, editLabelProvider)
              {
                @Override
                protected Object openDialogBox(Control cellEditorWindow)
                {
                  FeatureEditorDialog dialog = new FeatureEditorDialog(
                    cellEditorWindow.getShell(),
                    editLabelProvider,
                    object,
                    eDataType,
                    (List<?>)doGetValue(),
                    getDisplayName(),
                    null,
                    itemPropertyDescriptor.isMultiLine(object),
                    false);
                  dialog.open();
                  return dialog.getResult();
                }
              };
          }
          else if (eDataType.getInstanceClass() == Boolean.class || eDataType.getInstanceClass() == Boolean.TYPE)
          {
            result = new ExtendedComboBoxCellEditor(
            		parent,
              Arrays.asList(new Object []{ Boolean.FALSE, Boolean.TRUE }),
              getEditLabelProvider(),
              itemPropertyDescriptor.isSortChoices(object));
          }
          else
          {
            result = createEDataTypeCellEditor(eDataType, parent);
          }
          
        } else {
			// case of unserializable value TODO make it pluggable ?
	        result = super.createPropertyEditor(parent);
        }
        return result;
	}

}
