/* ColorChooser.java - a Java class for a color choosing dialog for OpenOffice.org
 *
 * Copyright (C) 2008  Dietmar Hiller, dhiller

    This program 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; version 3 of the License.

    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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License along with this program; if not, 
    see <http://www.gnu.org/licenses/>.
 *
 * Created on 5. Mai 2008, 21:34
 *
 */

package name.dhiller.ooo.ColorChooser;

import com.sun.star.awt.*;
import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.lib.uno.helper.WeakBase;
import com.sun.star.lib.uno.helper.Factory;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.lang.XSingleComponentFactory;
import com.sun.star.lang.XServiceInfo;
import com.sun.star.registry.XRegistryKey;
import com.sun.star.report.XImageControl;
import com.sun.star.uno.XComponentContext;
import com.sun.star.uno.UnoRuntime;

import java.awt.Color;

/** Colordialog for OpenOffice.org
 * @author dhiller
 * @version 080507
 * @since OOo 2.0.4 (dialog handling, see http://api.openoffice.org/docs/DevelopersGuide/Components/Components.xhtml ch. 4.11)
 */
public final class ColorChooser extends WeakBase
    implements XDialogEventHandler
{
    private final XComponentContext m_xContext;
    private XDialog m_xDialog;
    private XControlContainer m_xCC;
    private XScrollBar m_xDlgHue;
    private XNumericField m_xDlgSat;
    private XNumericField m_xDlgVal;
    private XPropertySet m_xrColorPS;
    private Color m_initialColor;
    private Color m_returnColor;
    
    /** Creates a new instance of ColorChooser */
    public ColorChooser(XComponentContext xContext) {
        m_xContext = xContext;
    }

    /** create ColorDialog and execute
     * @param sDlgDir - URL of directory with dialog
     * @param sDlgName - Name of dialog
     * @param sDlgHue - URL to image of hue
     * @param initialColor
     * @since OpenOffice.org 2.0.4
     * @return Color final color
     * @exception com.sun.star.lang.IllegalArgumentException 
     * @exception com.sun.star.uno.Exception 
     */
    // http://api.openoffice.org/docs/common/ref/com/sun/star/awt/XDialogProvider2.html
    public Color executeDialog(String sDlgDir, String sDlgName, String sDlgHue, 
            Color initialColor) {
        try {
            final XMultiComponentFactory xFact = m_xContext.getServiceManager();                      
            final Object xObject = xFact.createInstanceWithContext(
                        "com.sun.star.awt.DialogProvider2", m_xContext);
            final XDialogProvider2 aDialogProvider = (XDialogProvider2) 
                    UnoRuntime.queryInterface(XDialogProvider2.class, xObject);
            m_xDialog = aDialogProvider.createDialogWithHandler
                    (sDlgDir+"/"+sDlgName, this);
            
            Init(m_xDialog, sDlgDir+"/"+sDlgHue,initialColor);
            
            short nReturnValue = m_xDialog.execute();
            
            if (nReturnValue == 1) {                                // okay
                    m_returnColor = getColor(); }
        } catch (com.sun.star.lang.IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (com.sun.star.uno.Exception ex) {
            ex.printStackTrace();
        }
        return m_returnColor;
    }
    
    /**
     * Initialize the Dialog (used internally only)
     * @param theDialog
     * @param sURLHue URL to hue file
     * @param initialColor
     */
    private void Init(XDialog theDialog, String sURLHue, Color initialColor) {
       m_initialColor = initialColor;
       m_xCC = (XControlContainer)UnoRuntime.queryInterface(XControlContainer.class, 
               theDialog);
                                                    // always useful controls etc
       final XControl xDlgHueCtrl = m_xCC.getControl("dlgHue");
       m_xDlgHue = (XScrollBar) UnoRuntime.queryInterface(XScrollBar.class, xDlgHueCtrl);
       
       final XControl xDlgSatCtrl = m_xCC.getControl("dlgSat");
       m_xDlgSat = (XNumericField) UnoRuntime.queryInterface(XNumericField.class, xDlgSatCtrl);

       final XControl xDlgValCtrl = m_xCC.getControl("dlgVal");
       m_xDlgVal = (XNumericField) UnoRuntime.queryInterface(XNumericField.class, xDlgValCtrl);
       
       final XControl xrColor = m_xCC.getControl("rColor");
       final XControlModel xrColorModel = xrColor.getModel();
       m_xrColorPS = (XPropertySet)UnoRuntime.queryInterface
               (XPropertySet.class, xrColorModel );
                                                                    // Colorbar
       final XControl xImgHue = m_xCC.getControl("imgHue");
       final XControlModel xImgHueModel = xImgHue.getModel();
       final XPropertySet xPS = (XPropertySet)UnoRuntime.queryInterface
               (XPropertySet.class, xImgHueModel );
        try {
            xPS.setPropertyValue( "ImageURL", sURLHue);
        } catch (UnknownPropertyException ex) {
            ex.printStackTrace();
        } catch (PropertyVetoException ex) {
            ex.printStackTrace();
        } catch (WrappedTargetException ex) {
            ex.printStackTrace();
        } catch (com.sun.star.lang.IllegalArgumentException ex) {
            ex.printStackTrace();
        }
       setColor(initialColor);
    }
    
    /** called from the dialog to handle events
     * there is no need to call it directly
     * @param xDialog the dialog instance that generated the event
     * @param aEvent object derived from ::com::sun::star::lang::EventObject
     * @param aEventString the name of the function which is to be called
     * @return true if the event was handled, otherwise false.
     * interface XDialogEventHandler
     */
    public boolean callHandlerMethod(XDialog xDialog, Object aEvent, String aEventString ) {
        boolean returnValue = false;
        if (aEventString.equals("DlgColorHSV")) {           // any color button  
            Color gotColor = getColor();
            setPreview(gotColor);
            returnValue = true;
        }
        else if (aEventString.equals("DlgOkay")) {          // BOK
            m_returnColor = getColor();
            m_xDialog.endExecute();
            returnValue = true;
        }
        else if (aEventString.equals("DlgCancel")) {        // BCancel
            m_returnColor = m_initialColor;
            m_xDialog.endExecute();
            returnValue = true;          
        }
        else if (aEventString.equals("DlgReset")) {         // BReset
            setColor(m_initialColor);
            returnValue = true;            
        }
        return returnValue;
    } 
    
    /** getSupportedMethodNames
     * there is no need to call it directly
     * interface XDialogEventHandler
     */
    public String[] getSupportedMethodNames() {
	String[] retValue= new String[4];
	retValue[0]= "DlgOkay";     // BOK
	retValue[1]= "DlgCancel";   // BCancel
        retValue[2]= "DlgReset";    // BReset
        retValue[3]= "DlgColorHSV"; // any color button    
	return retValue;
    }
    
    /** gets the Color from the dialog
     * @return Color
     */
    private Color getColor() {
        float hue = (float) m_xDlgHue.getValue() / 360.0f;
        float sat = (float) m_xDlgSat.getValue() / 100.0f;
        float val = (float) m_xDlgVal.getValue() / 100.0f;
        Color workColor = new Color(0);
        Color gotColor = Color.getHSBColor(hue, sat, val);
        return gotColor;
    }

    /** display color values
     * Hue: 0..360, Saturation: 0..100, Value/Brightness: 0..100
     * @param initialColor
     */
    private void setColor(Color initialColor) {
        float[] colorHSB = initialColor.RGBtoHSB( initialColor.getRed(), 
                initialColor.getGreen(), initialColor.getBlue(), null);
        m_xDlgHue.setValue(Math.round(colorHSB[0]*360));
        m_xDlgSat.setValue(Math.round(colorHSB[1]*100));
        m_xDlgVal.setValue(Math.round(colorHSB[2]*100));
        setPreview(initialColor);
    }
    
    /** set color of preview bar
     * @param color color to be set
     * @exception UnknownPropertyException Property "BackgroundColor" not available
     * @exception PropertyVetoException Property "BackgroundColor" not available
     * @exception WrappedTargetException at setPropertyValue "BackgroundColor"
     * @exception com.sun.star.lang.IllegalArgumentException at setPropertyValue "BackgroundColor"
     */
    private void setPreview(Color color) {
        try {
            m_xrColorPS.setPropertyValue( "BackgroundColor", Math.round(color.getRed()*256*256
                    +color.getGreen()*256 + color.getBlue()));
        } catch (UnknownPropertyException ex) {
            ex.printStackTrace();
        } catch (PropertyVetoException ex) {
            ex.printStackTrace();
        } catch (WrappedTargetException ex) {
            ex.printStackTrace();
        } catch (com.sun.star.lang.IllegalArgumentException ex) {
            ex.printStackTrace();
        }
    }
    
    /** returns the version of this class
     * this function MUST be maintained for every modification
     * @return Version in the format YYMMDD-<name of developer>
     */
    public String getVersion() {
        return ("080507-DHiller");
    }
    
}
