/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the Apache
 * License, Version 2.0. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */
package org.geomajas.sld.editor.expert.common.client;

import org.geomajas.sld.editor.expert.common.client.model.SldManager;
import org.geomajas.sld.editor.expert.common.client.model.SldManagerImpl;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;

/**
 * Widget Factory class.
 *
 * @author David Debuck
 *
 */
public final class SldEditor {

	private static SldEditor instance;

	private SldEditorViewFactory viewFactory;

	private SldEditorClientBundleFactory bundleFactory;

	private SldEditorEventBusFactory eventBusFactory;

	private SldEditorServiceFactory sldEditorServiceFactory;

	private SldManager sldManager;

	private EventBus eventBus;

	/**
	 * SldEditor Constructor.
	 */
	private SldEditor() {
	}

	/**
	 * SldEditor Constructor.
	 *
	 * @return instance of SldEditor
	 */
	public static SldEditor getInstance() {
		if (instance == null) {
			instance = new SldEditor();
		}
		return instance;
	}

	/**
	 * Set an instance of this class.
	 *
	 * @param instance
	 */
	public static void setInstance(SldEditor instance) {
		SldEditor.instance = instance;
	}

	/**
	 * Factory for the Sld Editor Client Bundle.
	 *
	 * @return SldEditorClientBundleFactory
	 */
	public SldEditorClientBundleFactory getBundleFactory() {
		if (bundleFactory == null) {
			bundleFactory = GWT.create(SldEditorClientBundleFactory.class);
		}
		return bundleFactory;
	}

	/**
	 * Factory for the Sld Editor View.
	 *
	 * @return SldEditorViewFactory
	 */
	public SldEditorViewFactory getViewFactory() {
		if (viewFactory == null) {
			viewFactory = GWT.create(SldEditorViewFactory.class);
		}
		return viewFactory;
	}

	/**
	 * Factory for the Sld Editor EventBus.
	 *
	 * @return SldEditorEventBusFactory
	 */
	public SldEditorEventBusFactory getSldEditorEventBusFactory() {
		if (eventBusFactory == null) {
			eventBusFactory = GWT.create(SldEditorEventBusFactory.class);
		}
		return eventBusFactory;
	}

	/**
	 * Factory for the Sld Editor Service.
	 *
	 * @return SldEditorServiceFactory
	 */
	public SldEditorServiceFactory getSldEditorServiceFactory() {
		if (sldEditorServiceFactory == null) {
			sldEditorServiceFactory = GWT.create(SldEditorServiceFactory.class);
		}
		return sldEditorServiceFactory;
	}

	public EventBus getEventBus() {
		if (eventBus == null) {
			eventBus = getSldEditorEventBusFactory().createSldEditorWidgetEventBus();
		}
		return eventBus;
	}

	public void setEventBus(EventBus eventBus) {
		this.eventBus = eventBus;
	}

	/**
	 * Create an instance of the SldManager.
	 *
	 * @return the SldManager
	 */
	public SldManager getSldManager() {
		if (sldManager == null) {
			sldManager = new SldManagerImpl(getEventBus(), getSldEditorServiceFactory().createSldGwtServiceAsync());
		}
		return sldManager;
	}

}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import java.io.PrintStream;

import javax.annotation.Nonnull;

/**
 * Decompose a floating-point value into its parts according to the IEEE 754
 * standard.
 */
public class IEEE754
{
  /** sign bit as a string */
  private String m_sSignBit;
  /** exponent bits as a string */
  private String m_sExponentBits;
  /** fraction bits as a string */
  private String m_sFractionBits;
  /** implied bit as a string */
  private String m_sImpliedBit;

  /** biased exponent value */
  private int m_nBiased;
  /** fraction value */
  private long m_nFraction;

  /** exponent bias */
  private int m_nBias;

  /** float number value */
  private float m_fFloatValue;
  /** double number value */
  private double m_dDoubleValue;

  /**
   * true if number value is zero
   */
  private boolean m_bIsZero;
  /**
   * true if reserved exponent value
   */
  private boolean m_bIsReserved;
  /**
   * true if number type is double
   */
  private final boolean m_bIsDouble;
  /**
   * true if denormalized number value
   */
  private boolean m_bIsDenormalized;

  // --------------//
  // Constructors //
  // --------------//

  /**
   * Constructor. Decompose a float value.
   *
   * @param value
   *        the float value to decompose
   */
  public IEEE754 (final float value)
  {
    // Convert the value to a character array of '0' and '1'.
    final char bits[] = _toCharBitArray (Float.floatToIntBits (value), 32);

    m_fFloatValue = value;
    m_bIsDouble = false;

    _decompose (bits,
                IEEE754Constants.FLOAT_EXPONENT_BIAS,
                IEEE754Constants.FLOAT_EXPONENT_RESERVED,
                IEEE754Constants.FLOAT_SIGN_INDEX,
                IEEE754Constants.FLOAT_SIGN_SIZE,
                IEEE754Constants.FLOAT_EXPONENT_INDEX,
                IEEE754Constants.FLOAT_EXPONENT_SIZE,
                IEEE754Constants.FLOAT_FRACTION_INDEX,
                IEEE754Constants.FLOAT_FRACTION_SIZE);
  }

  /**
   * Constructor. Decompose a double value.
   *
   * @param value
   *        the double-precision value to decompose
   */
  public IEEE754 (final double value)
  {
    // Convert the value to a character array of '0' and '1'.
    final char bits[] = _toCharBitArray (Double.doubleToLongBits (value), 64);

    m_dDoubleValue = value;
    m_bIsDouble = true;

    _decompose (bits,
                IEEE754Constants.DOUBLE_EXPONENT_BIAS,
                IEEE754Constants.DOUBLE_EXPONENT_RESERVED,
                IEEE754Constants.DOUBLE_SIGN_INDEX,
                IEEE754Constants.DOUBLE_SIGN_SIZE,
                IEEE754Constants.DOUBLE_EXPONENT_INDEX,
                IEEE754Constants.DOUBLE_EXPONENT_SIZE,
                IEEE754Constants.DOUBLE_FRACTION_INDEX,
                IEEE754Constants.DOUBLE_FRACTION_SIZE);
  }

  /**
   * Constructor. Reconstitute a float value.
   *
   * @param sign
   *        the sign bit value, 0 or 1
   * @param biasedExponent
   *        the biased exponent value, 0..255
   * @param fraction
   *        the fraction bits
   * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
   */
  public IEEE754 (final int sign, final int biasedExponent, final FloatFraction fraction) throws IEEE754Exception
  {
    // Check the sign.
    if ((sign != 0) && (sign != 1))
    {
      throw new IEEE754Exception ("Invalid sign bit.");
    }

    validateFloatBiasedExponent (biasedExponent);

    // Consolidate the parts. First the sign ...
    int intBits = sign;

    // ... then the biased exponent value ...
    intBits <<= IEEE754Constants.FLOAT_EXPONENT_SIZE;
    intBits += biasedExponent;

    // ... and finally the fraction value.
    intBits <<= IEEE754Constants.FLOAT_FRACTION_SIZE;
    intBits += fraction.toInt ();

    // Convert to the float value.
    m_fFloatValue = Float.intBitsToFloat (intBits);
    m_bIsDouble = false;

    // Convert the value to a character array of '0' and '1'.
    final char bits[] = _toCharBitArray (intBits, 32);

    _decompose (bits,
                IEEE754Constants.FLOAT_EXPONENT_BIAS,
                IEEE754Constants.FLOAT_EXPONENT_RESERVED,
                IEEE754Constants.FLOAT_SIGN_INDEX,
                IEEE754Constants.FLOAT_SIGN_SIZE,
                IEEE754Constants.FLOAT_EXPONENT_INDEX,
                IEEE754Constants.FLOAT_EXPONENT_SIZE,
                IEEE754Constants.FLOAT_FRACTION_INDEX,
                IEEE754Constants.FLOAT_FRACTION_SIZE);
  }

  /**
   * Constructor. Reconstitute a double value.
   *
   * @param sign
   *        the sign bit value, 0 or 1
   * @param biasedExponent
   *        the biased exponent value, 0..2047
   * @param fraction
   *        the fraction bits
   * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
   */
  public IEEE754 (final int sign, final int biasedExponent, final DoubleFraction fraction) throws IEEE754Exception
  {
    // Check the sign.
    if ((sign != 0) && (sign != 1))
    {
      throw new IEEE754Exception ("Invalid sign bit.");
    }

    validateDoubleBiasedExponent (biasedExponent);

    // Consolidate the parts. First the sign ...
    long longBits = sign;

    // ... then the biased exponent value ...
    longBits <<= IEEE754Constants.DOUBLE_EXPONENT_SIZE;
    longBits += biasedExponent;

    // ... and finally the fraction value.
    longBits <<= IEEE754Constants.DOUBLE_FRACTION_SIZE;
    longBits += fraction.toLong ();

    // Convert to the double value.
    m_dDoubleValue = Double.longBitsToDouble (longBits);
    m_bIsDouble = true;

    // Convert the value to a character array of '0' and '1'.
    final char bits[] = _toCharBitArray (longBits, 64);

    _decompose (bits,
                IEEE754Constants.DOUBLE_EXPONENT_BIAS,
                IEEE754Constants.DOUBLE_EXPONENT_RESERVED,
                IEEE754Constants.DOUBLE_SIGN_INDEX,
                IEEE754Constants.DOUBLE_SIGN_SIZE,
                IEEE754Constants.DOUBLE_EXPONENT_INDEX,
                IEEE754Constants.DOUBLE_EXPONENT_SIZE,
                IEEE754Constants.DOUBLE_FRACTION_INDEX,
                IEEE754Constants.DOUBLE_FRACTION_SIZE);
  }

  // -------------------------//
  // Methods to return parts //
  // -------------------------//

  /**
   * Return the float value.
   *
   * @return the float value
   */
  public float floatValue ()
  {
    return m_fFloatValue;
  }

  /**
   * Return the double value.
   *
   * @return the double value
   */
  public double doubleValue ()
  {
    return m_dDoubleValue;
  }

  /**
   * Return the biased value of the exponent.
   *
   * @return the unbiased exponent value
   */
  public int biasedExponent ()
  {
    return m_nBiased;
  }

  /**
   * Return the unbiased value of the exponent.
   *
   * @return the unbiased exponent value
   */
  public int unbiasedExponent ()
  {
    return m_bIsDenormalized ? -m_nBias + 1 : m_nBiased - m_nBias;
  }

  /**
   * Return the sign as a string of '0' and '1'.
   *
   * @return the string
   */
  public String signBit ()
  {
    return m_sSignBit;
  }

  /**
   * Return the exponent as a string of '0' and '1'.
   *
   * @return the string
   */
  public String exponentBits ()
  {
    return m_sExponentBits;
  }

  /**
   * Return the fraction as a string of '0' and '1'.
   *
   * @return the string
   */
  public String fractionBits ()
  {
    return m_sFractionBits;
  }

  /**
   * Return the significand as a string of '0', '1' and '.'.
   *
   * @return the string
   */
  public String significandBits ()
  {
    return m_sImpliedBit + "." + m_sFractionBits;
  }

  /**
   * Return whether or not the value is zero.
   *
   * @return true if zero, else false
   */
  public boolean isZero ()
  {
    return m_bIsZero;
  }

  /**
   * Return whether or not the value is a double.
   *
   * @return true if a double, else false
   */
  public boolean isDouble ()
  {
    return m_bIsDouble;
  }

  /**
   * Return whether or not the value is denormalized.
   *
   * @return true if denormalized, else false
   */
  public boolean isDenormalized ()
  {
    return m_bIsDenormalized;
  }

  /**
   * Return whether or not the exponent value is reserved.
   *
   * @return true if reserved, else false
   */
  public boolean isExponentReserved ()
  {
    return m_bIsReserved;
  }

  // -----------------------//
  // Decomposition methods //
  // -----------------------//

  /**
   * Convert a long value into a character array of '0' and '1' that represents
   * the value in base 2.
   *
   * @param pvalue
   *        the long value
   * @param size
   *        the array size
   * @return the character array
   */
  private static char [] _toCharBitArray (final long pvalue, final int size)
  {
    long value = pvalue;
    final char bits[] = new char [size];

    // Convert each bit from right to left.
    for (int i = size - 1; i >= 0; --i)
    {
      bits[i] = (value & 1) == 0 ? '0' : '1';
      value >>>= 1;
    }

    return bits;
  }

  /**
   * Decompose a floating-point value into its parts.
   *
   * @param bits
   *        the character array of '0' and '1' that represents the value in base
   *        2
   * @param bias
   *        the exponent bias value
   * @param reserved
   *        the reserved exponent value (other than 0)
   * @param signIndex
   *        the index of the sign bit
   * @param signSize
   *        the size of the sign bit
   * @param exponentIndex
   *        the index of the exponent
   * @param exponentSize
   *        the size of the exponent
   * @param fractionIndex
   *        the index of the fraction
   * @param fractionSize
   *        the size of the fraction
   */
  private void _decompose (final char [] bits,
                           final int bias,
                           final int reserved,
                           final int signIndex,
                           final int signSize,
                           final int exponentIndex,
                           final int exponentSize,
                           final int fractionIndex,
                           final int fractionSize)
  {
    this.m_nBias = bias;

    // Extract the individual parts as strings of '0' and '1'.
    m_sSignBit = new String (bits, signIndex, signSize);
    m_sExponentBits = new String (bits, exponentIndex, exponentSize);
    m_sFractionBits = new String (bits, fractionIndex, fractionSize);

    try
    {
      m_nBiased = Integer.parseInt (m_sExponentBits, 2);
      m_nFraction = Long.parseLong (m_sFractionBits, 2);
    }
    catch (final NumberFormatException ex)
    {}

    m_bIsZero = (m_nBiased == 0) && (m_nFraction == 0);
    m_bIsDenormalized = (m_nBiased == 0) && (m_nFraction != 0);
    m_bIsReserved = (m_nBiased == reserved);

    m_sImpliedBit = m_bIsDenormalized || m_bIsZero || m_bIsReserved ? "0" : "1";
  }

  /**
   * Print the decomposed parts of the value.
   */
  public void print (@Nonnull final PrintStream aPW)
  {
    aPW.println ("------------------------------");

    // Print the value.
    if (isDouble ())
      aPW.println ("double value = " + doubleValue ());
    else
      aPW.println ("float value = " + floatValue ());

    // Print the sign.
    aPW.print ("sign=" + signBit ());

    // Print the bit representation of the exponent and its
    // biased and unbiased values. Indicate whether the value
    // is denormalized, or whether the exponent is reserved.
    aPW.print (", exponent=" + exponentBits () + " (biased=" + biasedExponent ());

    if (isZero ())
      aPW.println (", zero)");
    else
      if (isExponentReserved ())
        aPW.println (", reserved)");
      else
        if (isDenormalized ())
          aPW.println (", denormalized, use " + unbiasedExponent () + ")");
        else
          aPW.println (", normalized, unbiased=" + unbiasedExponent () + ")");

    // Print the significand.
    aPW.println ("significand=" + significandBits ());
  }

  // --------------------------------//
  // Compute and validate exponents //
  // --------------------------------//

  /**
   * Compute the value of the float biased exponent given the unbiased value.
   *
   * @param unbiased
   *        the unbiased exponent value
   * @return the biased exponent value
   */
  public static int toFloatBiasedExponent (final int unbiased)
  {
    return unbiased + IEEE754Constants.FLOAT_EXPONENT_BIAS;
  }

  /**
   * Compute the value of the float unbiased exponent given the biased value.
   *
   * @param biased
   *        the biased exponent value
   * @return the unbiased exponent value
   */
  public static int toFloatUnbiasedExponent (final int biased)
  {
    return biased == 0 ? -IEEE754Constants.FLOAT_EXPONENT_BIAS + 1 : biased - IEEE754Constants.FLOAT_EXPONENT_BIAS;
  }

  /**
   * Compute the value of the double biased exponent given the unbiased value.
   *
   * @param unbiased
   *        the unbiased exponent value
   * @return the biased exponent value
   */
  public static int toDoubleBiasedExponent (final int unbiased)
  {
    return unbiased + IEEE754Constants.DOUBLE_EXPONENT_BIAS;
  }

  /**
   * Compute the value of the double unbiased exponent given the biased value.
   *
   * @param biased
   *        the biased exponent value
   * @return the unbiased exponent value
   */
  public static int toDoubleUnbiasedExponent (final int biased)
  {
    return biased == 0 ? -IEEE754Constants.DOUBLE_EXPONENT_BIAS + 1 : biased - IEEE754Constants.DOUBLE_EXPONENT_BIAS;
  }

  /**
   * Validate the value of the float biased exponent value.
   *
   * @param biased
   *        the biased exponent value
   * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
   */
  public static void validateFloatBiasedExponent (final int biased) throws IEEE754Exception
  {
    if ((biased < 0) || (biased > IEEE754Constants.FLOAT_EXPONENT_RESERVED))
    {
      throw new IEEE754Exception ("The biased exponent value should be " +
                                  "0 through " +
                                  IEEE754Constants.FLOAT_EXPONENT_RESERVED +
                                  ".");
    }
  }

  /**
   * Validate the value of the float unbiased exponent value.
   *
   * @param unbiased
   *        the unbiased exponent value
   * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
   */
  public static void validateFloatUnbiasedExponent (final int unbiased) throws IEEE754Exception
  {
    if ((unbiased < -IEEE754Constants.FLOAT_EXPONENT_BIAS + 1) || (unbiased > IEEE754Constants.FLOAT_EXPONENT_BIAS))
    {
      throw new IEEE754Exception ("The unbiased exponent value should be " +
                                  -(IEEE754Constants.FLOAT_EXPONENT_BIAS - 1) +
                                  " through " +
                                  IEEE754Constants.FLOAT_EXPONENT_BIAS +
                                  ".");
    }
  }

  /**
   * Validate the value of the double biased exponent value.
   *
   * @param biased
   *        the biased exponent value
   * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
   */
  public static void validateDoubleBiasedExponent (final int biased) throws IEEE754Exception
  {
    if ((biased < 0) || (biased > IEEE754Constants.DOUBLE_EXPONENT_RESERVED))
    {
      throw new IEEE754Exception ("The biased exponent value should be " +
                                  "0 through " +
                                  IEEE754Constants.DOUBLE_EXPONENT_RESERVED +
                                  ".");
    }
  }

  /**
   * Validate the value of the double unbiased exponent value.
   *
   * @param unbiased
   *        the unbiased exponent value
   * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
   */
  public static void validateDoubleUnbiasedExponent (final int unbiased) throws IEEE754Exception
  {
    if ((unbiased < -IEEE754Constants.DOUBLE_EXPONENT_BIAS + 1) || (unbiased > IEEE754Constants.DOUBLE_EXPONENT_BIAS))
    {
      throw new IEEE754Exception ("The unbiased exponent value should be " +
                                  -(IEEE754Constants.DOUBLE_EXPONENT_BIAS - 1) +
                                  " through " +
                                  IEEE754Constants.DOUBLE_EXPONENT_BIAS +
                                  ".");
    }
  }

  // ------------------------------//
  // Nested decomposition classes //
  // ------------------------------//

  /**
   * IEEE 754 exception.
   */
  public static class IEEE754Exception extends java.lang.Exception
  {
    public IEEE754Exception (final String message)
    {
      super (message);
    }
  }

  /**
   * Abstract base class for the IEEE 754 part classes.
   */
  private static abstract class AbstractPart
  {
    /** the part buffer */
    private final StringBuilder m_aPart;

    /**
     * Constructor.
     *
     * @param size
     *        the bit size of the part
     * @param bits
     *        the string of character bits '0' and '1'
     * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
     */
    private AbstractPart (final int size, final String bits) throws IEEE754Exception
    {
      if (size <= 0)
      {
        throw new IEEE754Exception ("Invalid part size: " + size);
      }

      final int length = bits.length ();
      m_aPart = new StringBuilder (size);

      // String length matches part size.
      if (length == size)
      {
        m_aPart.append (bits);
        _validate ();
      }

      // String length < part size: Pad with '0'.
      else
        if (length < size)
        {
          m_aPart.append (bits);
          _validate ();
          for (int i = length; i < size; ++i)
            m_aPart.append ('0');
        }

        // String length > part size: Truncate at the right end.
        else
        {
          m_aPart.append (bits.substring (0, size));
          _validate ();
        }
    }

    /**
     * Convert the part to an integer value.
     *
     * @return the integer value
     * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
     *         if the binary number format is invalid
     */
    protected int toInt () throws IEEE754Exception
    {
      try
      {
        return Integer.parseInt (m_aPart.toString (), 2);
      }
      catch (final NumberFormatException ex)
      {
        throw new IEEE754Exception ("Invalid binary number format: " + m_aPart.toString ());
      }
    }

    /**
     * Convert the part to an long value.
     *
     * @return the long value
     * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
     *         if the binary number format is invalid
     */
    protected long toLong () throws IEEE754Exception
    {
      try
      {
        return Long.parseLong (m_aPart.toString (), 2);
      }
      catch (final NumberFormatException ex)
      {
        throw new IEEE754Exception ("Invalid binary number format: " + m_aPart.toString ());
      }
    }

    /**
     * Return the part as a string of characters '0' and '1'.
     */
    @Override
    public String toString ()
    {
      return m_aPart.toString ();
    }

    /**
     * Validate that the part consists only of '0' and '1'.
     *
     * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
     */
    private void _validate () throws IEEE754Exception
    {
      final int length = m_aPart.length ();

      for (int i = 0; i < length; ++i)
      {
        final char bit = m_aPart.charAt (i);
        if ((bit != '0') && (bit != '1'))
        {
          throw new IEEE754Exception ("Invalid fraction bit string.");
        }
      }
    }
  }

  /**
   * The IEEE 754 fraction part for a float.
   */
  public static class FloatFraction extends AbstractPart
  {
    /**
     * Constructor.
     *
     * @param bits
     *        the string of character bits '0' and '1'
     * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
     */
    public FloatFraction (final String bits) throws IEEE754Exception
    {
      super (IEEE754Constants.FLOAT_FRACTION_SIZE, bits);
    }
  }

  /**
   * The IEEE 754 fraction part for a double.
   */
  public static class DoubleFraction extends AbstractPart
  {
    /**
     * Constructor.
     *
     * @param bits
     *        the string of character bits '0' and '1'
     * @throws com.helger.numbercruncher.mathutils.IEEE754.IEEE754Exception
     */
    public DoubleFraction (final String bits) throws IEEE754Exception
    {
      super (IEEE754Constants.DOUBLE_FRACTION_SIZE, bits);
    }
  }
}


/*
 * This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
 *
 * Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
 *
 * The program is available in open source according to the Apache
 * License, Version 2.0. All contributions in this program are covered
 * by the Geomajas Contributors License Agreement. For full licensing
 * details, see LICENSE.txt in the project root.
 */
package org.geomajas.sld.editor.expert.common.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import org.geomajas.annotation.Api;
import org.geomajas.annotation.UserImplemented;
import org.geomajas.sld.editor.expert.common.client.model.SldGwtService;
import org.geomajas.sld.editor.expert.common.client.model.SldGwtServiceAsync;

/**
 * Sld Editor Service Factory class.
 *
 * @author David Debuck
 * @since Version 1.0.0
 *
 */
@Api(allMethods = true)
@UserImplemented
public class SldEditorServiceFactory {

	private SldGwtServiceAsync service;

	/**
	 * SldEditorServiceFactory constructor.
	 *
	 * @return SldGwtServiceAsync
	 */
	public SldGwtServiceAsync createSldGwtServiceAsync() {

		this.service = GWT.create(SldGwtService.class);

		ServiceDefTarget endpoint = (ServiceDefTarget) service;
		endpoint.setServiceEntryPoint(GWT.getHostPageBaseURL() + "d/sldTemplates");

		return service;

	}

}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import java.util.Random;

/**
 * Utility class that generates normally-distributed random values using several
 * algorithms.
 */
public class RandomNormal
{
  /** mean */
  private float m_fMean;
  /** standard deviation */
  private float m_fStddev;

  /**
   * next random value from the polar algorithm
   */
  private float m_fNextPolar;
  /**
   * true if the next polar value is available
   */
  private boolean m_bHaveNextPolar = false;

  /** generator of uniformly-distributed random values */
  private static final Random GENERATOR = new Random ();

  /**
   * Set the mean and standard deviation.
   *
   * @param mean
   *        the mean
   * @param stddev
   *        the standard deviation
   */
  public void setParameters (final float mean, final float stddev)
  {
    m_fMean = mean;
    m_fStddev = stddev;
  }

  /**
   * Compute the next random value using the Central Limit Theorem, which states
   * that the averages of sets of uniformly-distributed random values are
   * normally distributed.
   */
  public float nextCentral ()
  {
    // Average 12 uniformly-distributed random values.
    float sum = 0.0f;
    for (int j = 0; j < 12; ++j)
      sum += GENERATOR.nextFloat ();

    // Subtract 6 to center about 0.
    return m_fStddev * (sum - 6) + m_fMean;
  }

  /**
   * Compute the next randomn value using the polar algorithm. Requires two
   * uniformly-distributed random values in [-1, +1). Actually computes two
   * random values and saves the second one for the next invokation.
   */
  public float nextPolar ()
  {
    // If there's a saved value, return it.
    if (m_bHaveNextPolar)
    {
      m_bHaveNextPolar = false;
      return m_fNextPolar;
    }

    // point coordinates and their radius
    float u1, u2, r;

    do
    {
      // u1 and u2 will be uniformly-distributed
      // random values in [-1, +1).
      u1 = 2 * GENERATOR.nextFloat () - 1;
      u2 = 2 * GENERATOR.nextFloat () - 1;

      // Want radius r inside the unit circle.
      r = u1 * u1 + u2 * u2;
    } while (r >= 1);

    // Factor incorporates the standard deviation.
    final float factor = (float) (m_fStddev * Math.sqrt (-2 * Math.log (r) / r));

    // v1 and v2 are normally-distributed random values.
    final float v1 = factor * u1 + m_fMean;
    final float v2 = factor * u2 + m_fMean;

    // Save v1 for next time.
    m_fNextPolar = v1;
    m_bHaveNextPolar = true;

    return v2;
  }

  // Constants for the ratio algorithm.
  private static final float C1 = (float) Math.sqrt (8 / Math.E);
  private static final float C2 = (float) (4 * Math.exp (0.25));
  private static final float C3 = (float) (4 * Math.exp (-1.35));

  /**
   * Compute the next random value using the ratio algorithm. Requires two
   * uniformly-distributed random values in [0, 1).
   */
  public float nextRatio ()
  {
    float u, v, x, xx;

    do
    {
      // u and v are two uniformly-distributed random values
      // in [0, 1), and u != 0.
      while ((u = GENERATOR.nextFloat ()) == 0)
      {
        // try again if 0
      }
      v = GENERATOR.nextFloat ();

      // y coord of point (u, y)
      final float y = C1 * (v - 0.5f);

      // ratio of point's coords
      x = y / u;

      xx = x * x;
    } while ((xx > 5f - C2 * u) && // quick acceptance
             ((xx >= C3 / u + 1.4f) || // quick rejection
              (xx > (float) (-4 * Math.log (u)))) // final test
    );

    return m_fStddev * x + m_fMean;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.ICommonsList;

/**
 * Compute the Sieve of Eratosthenes and prime factors.
 */
public class PrimeFactors
{
  /**
   * Compute the Sieve of Eratosthenes.
   *
   * @param n
   *        the size of the sieve
   * @return the sieve as a boolean array (each element is true if the
   *         corresponding number is prime, false if the number is composite)
   */
  public static boolean [] primeSieve (final int n)
  {
    final int halfN = (n + 1) >> 1;
    final boolean sieve[] = new boolean [n + 1];

    // Initialize every integer from 2 onwards to prime.
    for (int i = 2; i <= n; ++i)
      sieve[i] = true;

    int prime = 2; // first prime number

    // Loop to create the sieve.
    while (prime < halfN)
    {

      // Mark as composites multiples of the prime.
      for (int composite = prime << 1; composite <= n; composite += prime)
        sieve[composite] = false;

      // Skip over composites to the next prime.
      while ((++prime < halfN) && (!sieve[prime]))
      {}
    }

    return sieve;
  }

  /**
   * Compute the prime factors of an integer value.
   *
   * @param pn
   *        the value to factor
   * @return an array of distinct prime factors
   */
  public static int [] factorsOf (final int pn)
  {
    int n = pn;
    final boolean isPrime[] = primeSieve (n); // primes <= n
    final ICommonsList <Integer> v = new CommonsArrayList<> ();

    // Loop to try prime divisors.
    for (int factor = 2; n > 1; ++factor)
    {
      if (isPrime[factor] && (n % factor == 0))
      {

        // Prime divisor found.
        v.add (Integer.valueOf (factor));

        // Factor out multiples of the divisor.
        do
        {
          n /= factor;
        } while (n % factor == 0);
      }
    }

    // Create an array of the distinct prime factors.
    final int factors[] = new int [v.size ()];
    for (int i = 0; i < v.size (); ++i)
    {
      factors[i] = v.get (i).intValue ();
    }
    return factors;
  }
}


/**
 * Copyright (C) 2014-2019 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.numbercruncher.mathutils;

import com.helger.commons.equals.EqualsHelper;

/**
 * The root finder class that implements the bisection algorithm.
 */
public class BisectionRootFinder extends AbstractRootFinder
{
  private static final int MAX_ITERS = 50;
  private static final float TOLERANCE = 100 * Epsilon.floatValue ();

  /** x-negative value */
  private float m_fXNeg;
  /** x-middle value */
  private float m_fXMid = Float.NaN;
  /** x-positive value */
  private float m_fXPos;
  /** previous x-middle value */
  private float m_fPrevXMid;
  /** f(xNeg) */
  private float m_fNeg;
  /** f(xMid) */
  private float m_fMid;
  /** f(xPos) */
  private float m_fPos;

  /**
   * Constructor.
   *
   * @param function
   *        the functions whose roots to find
   * @param xMin
   *        the initial x-value where the function is negative
   * @param xMax
   *        the initial x-value where the function is positive
   * @throws AbstractRootFinder.InvalidIntervalException
   *         in checkInterval
   */
  public BisectionRootFinder (final AbstractFunction function,
                              final float xMin,
                              final float xMax) throws AbstractRootFinder.InvalidIntervalException
  {
    super (function, MAX_ITERS);
    checkInterval (xMin, xMax);

    final float yMin = function.at (xMin);
    final float yMax = function.at (xMax);

    // Initialize xNeg, fNeg, xPos, and fPos.
    if (yMin < 0)
    {
      m_fXNeg = xMin;
      m_fXPos = xMax;
      m_fNeg = yMin;
      m_fPos = yMax;
    }
    else
    {
      m_fXNeg = xMax;
      m_fXPos = xMin;
      m_fNeg = yMax;
      m_fPos = yMin;
    }
  }

  // ---------//
  // Getters //
  // ---------//

  /**
   * Return the current value of x-negative.
   *
   * @return the value
   */
  public float getXNeg ()
  {
    return m_fXNeg;
  }

  /**
   * Return the current value of x-middle.
   *
   * @return the value
   */
  public float getXMid ()
  {
    return m_fXMid;
  }

  /**
   * Return the current value of x-positive.
   *
   * @return the value
   */
  public float getXPos ()
  {
    return m_fXPos;
  }

  /**
   * Return the current value of f(x-negative).
   *
   * @return the value
   */
  public float getFNeg ()
  {
    return m_fNeg;
  }

  /**
   * Return the current value of f(x-middle).
   *
   * @return the value
   */
  public float getFMid ()
  {
    return m_fMid;
  }

  /**
   * Return the current value of f(x-positive).
   *
   * @return the value
   */
  public float getFPos ()
  {
    return m_fPos;
  }

  // -----------------------------//
  // RootFinder method overrides //
  // -----------------------------//

  /**
   * Do the bisection iteration procedure.
   *
   * @param n
   *        the iteration count
   */
  @Override
  protected void doIterationProcedure (final int n)
  {
    if (n == 1)
      return; // already initialized

    if (m_fMid < 0)
    {
      m_fXNeg = m_fXMid; // the root is in the xPos half
      m_fNeg = m_fMid;
    }
    else
    {
      m_fXPos = m_fXMid; // the root is in the xNeg half
      m_fPos = m_fMid;
    }
  }

  /**
   * Compute the next position of xMid.
   */
  @Override
  protected void computeNextPosition ()
  {
    m_fPrevXMid = m_fXMid;
    m_fXMid = (m_fXNeg + m_fXPos) / 2;
    m_fMid = m_aFunction.at (m_fXMid);
  }

  /**
   * Check the position of xMid.
   *
   * @throws PositionUnchangedException
   */
  @Override
  protected void checkPosition () throws AbstractRootFinder.PositionUnchangedException
  {
    if (EqualsHelper.equals (m_fXMid, m_fPrevXMid))
    {
      throw new AbstractRootFinder.PositionUnchangedException ();
    }
  }

  /**
   * Indicate whether or not the algorithm has converged.
   *
   * @return true if converged, else false
   */
  @Override
  protected boolean hasConverged ()
  {
    return Math.abs (m_fMid) < TOLERANCE;
  }
}


/*
 * Copyright (C) 2013,2014 The Cat Hive Developers.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cathive.fx.cdi;

import javafx.application.Application;
import javafx.application.Platform;

import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.spi.*;
import javax.enterprise.util.AnnotationLiteral;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;

/**
 * This JavaFX extension makes sure that sub-classes of {@link com.cathive.fx.cdi.CdiApplication} can be
 * injected (using the {@link javax.inject.Inject @javax.inject.Inject} annotation).
 * @author Benjamin P. Jung
 */
@SuppressWarnings({ "UnusedDeclaration", "CdiManagedBeanInconsistencyInspection" })
class JavaFXExtension implements Extension {

    /** Logger for this instance. */
    private final Logger logger = Logger.getLogger(this.getClass().getName());

    /**
     * The JavaFX application instance to be provided by the CDI BeanManager.
     *
It is crucial that this field is populated (using {@link #setJavaFxApplication(CdiApplication)}
     * prior to initializing the CDI context.

     */
    static ThreadLocal<CdiApplication> JAVA_FX_APPLICATION = new ThreadLocal<>();

    private CdiApplicationBean<CdiApplication> JAVA_FX_APPLICATION_BEAN;

    /**
     * Sets the JavaFX application instance to be provided by the CDI BeanManager.
     * @param javaFxApplication
     *         The JavaFX application instance to be provided by the CDI BeanManager.
     */
    public static void setJavaFxApplication(final CdiApplication javaFxApplication) {

        final CountDownLatch latch = new CountDownLatch(1);
        Platform.runLater(() -> {
            JAVA_FX_APPLICATION.set(javaFxApplication);
            latch.countDown();
        });

        if (!Platform.isFxApplicationThread()) {
            try {
                latch.await();
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }

    }

    public static <T extends CdiApplication> T getJavaFxApplication() {

        final ValueLatch<CdiApplication> latch = new ValueLatch<>(1);
        Platform.runLater(() -> {
            latch.setValue(JAVA_FX_APPLICATION.get());
            latch.countDown();
        });
        if (!Platform.isFxApplicationThread()) {
            try {
                latch.await();
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }
        return (T) latch.getValue();
    }

    // ---- ==== CDI LIFECYCLE EVENTS ==== -----------------------------------------------------------------------------

    void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery beforeBeanDiscovery, final BeanManager beanManager) {

        if (getJavaFxApplication() == null) {
            throw new IllegalStateException("JavaFX application was not provided. Did you call FxCdiExtension.setJavaFxApplication(..)?");
        }

    }

    void processAnnotatedType(@Observes final ProcessAnnotatedType<? extends Application> pat, final BeanManager beanManager) {
        final Class<? extends Application> javaClass = pat.getAnnotatedType().getJavaClass();
        if (javaClass.equals(getJavaFxApplication().getClass())) {
            // We veto any sub-classes of CdiApplication to make sure, that the right bean
            // will be pulled into the dependency graph when using @Inject annotations.
            pat.veto();
        }
    }

    <X> void processInjectionTarget(@Observes final ProcessInjectionTarget<X> pit, final BeanManager beanManager) {
        final Class<X> javaClass = pit.getAnnotatedType().getJavaClass();
        if (javaClass.equals(getJavaFxApplication().getClass())) {

        }
    }

    <T, X> void processInjectionPoint(@Observes final ProcessInjectionPoint<T, X> pip, final BeanManager beanManager) {
    }

    void afterBeanDiscovery(@Observes final AfterBeanDiscovery abd, final BeanManager beanManager) {

        assert JAVA_FX_APPLICATION_BEAN == null;

        final AnnotatedType<CdiApplication> annotatedType = (AnnotatedType<CdiApplication>) beanManager.createAnnotatedType(getJavaFxApplication().getClass());
        final BeanAttributes<CdiApplication> beanAttributes = beanManager.createBeanAttributes(annotatedType);
        final InjectionTarget<CdiApplication> injectionTarget = beanManager.createInjectionTarget(annotatedType);

        // Obtains the one (and only) application instance to ever be used.
        final CdiApplication instance = getJavaFxApplication();

        // Constructs the bean used to provide instances of the JavaFX application instance.
        JAVA_FX_APPLICATION_BEAN = new CdiApplicationBean(instance, beanAttributes, injectionTarget);

        abd.addBean(JAVA_FX_APPLICATION_BEAN);

    }

    void afterDeploymentValidation(@Observes final  AfterDeploymentValidation adv, final BeanManager beanManager) {
        final CreationalContext<CdiApplication> creationalContext = beanManager.createCreationalContext(JAVA_FX_APPLICATION_BEAN);
        JAVA_FX_APPLICATION_BEAN.injectionTarget.inject(getJavaFxApplication(), creationalContext);
    }

    void beforeShutdown(@Observes final BeforeShutdown beforeShutdown, final BeanManager beanManager) {
        this.JAVA_FX_APPLICATION_BEAN = null;
    }

    /**
     * A simple wrapper class that helps us to get things up and running.
     * @author Benjamin P. Jung
     */
    static class CdiApplicationBean<T extends CdiApplication> implements Bean<T>, PassivationCapable {

        /** The scope to be used for our JavaFX application instance. */
        static final Class<? extends Annotation> SCOPE = Dependent.class;

        final T instance;
        final Set<Annotation> qualifiers;

        final BeanAttributes<T> beanAttributes;
        final InjectionTarget<T> injectionTarget;

        public CdiApplicationBean(final T instance, final BeanAttributes<T> beanAttributes, final InjectionTarget<T> injectionTarget) {

            super();

            this.instance = instance;

            this.qualifiers = new HashSet<>();
            this.qualifiers.add(new AnnotationLiteral<Any>() {});
            this.qualifiers.add(new AnnotationLiteral<Default>() {});

            this.beanAttributes = beanAttributes;
            this.injectionTarget = injectionTarget;

        }

        @Override
        public Class<?> getBeanClass() {
            return this.instance.getClass();
        }

        @Override
        public Set<InjectionPoint> getInjectionPoints() {
            return this.injectionTarget.getInjectionPoints();
        }

        @Override
        public boolean isNullable() {
            return false;
        }

        @Override
        public Set<Type> getTypes() {
            return this.beanAttributes.getTypes();
        }

        @Override
        public Set<Annotation> getQualifiers() {
            return this.qualifiers;
        }

        @Override
        public Class<? extends Annotation> getScope() {
            return SCOPE;
        }

        @Override
        public String getName() {
            return this.beanAttributes.getName();
        }

        @Override
        public Set<Class<? extends Annotation>> getStereotypes() {
            return this.beanAttributes.getStereotypes();
        }

        @Override
        public boolean isAlternative() {
            return this.beanAttributes.isAlternative();
        }

        @Override
        public T create(CreationalContext<T> creationalContext) {
            return this.instance;
        }

        @Override
        public void destroy(T instance, CreationalContext<T> creationalContext) {
            // TODO Should we call instance.stop() here? I actually don't think so...
        }

        @Override
        public String getId() {
            return this.instance.getClass().getName();
        }
    }

    /**
     * A simple countdown latch that can carry a value
     * @param <T>
     *     Type of the value to be carried.
     */
    private static class ValueLatch<T> extends CountDownLatch {

        /**
         * Constructs a {@code CountDownLatch} initialized with the given count.
         *
         * @param count the number of times {@link #countDown} must be invoked
         *              before threads can pass through {@link #await}
         * @throws IllegalArgumentException if {@code count} is negative
         */
        public ValueLatch(final int count) {
            super(count);
        }

        private T value;
        public T getValue() { return this.value; }
        public void setValue(final T value) { this.value = value; }

    }

}


package org.daisy.maven.xproc.calabash;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileOutputStream;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;

import static com.google.common.base.Objects.equal;
import com.google.common.collect.Iterators;

import com.xmlcalabash.core.XProcConfiguration;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.ReadablePipe;
import com.xmlcalabash.io.WritableDocument;
import com.xmlcalabash.model.RuntimeValue;
import com.xmlcalabash.runtime.XPipeline;
import com.xmlcalabash.util.Input;

import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.XdmNode;

import org.apache.xml.resolver.CatalogManager;
import org.apache.xml.resolver.tools.CatalogResolver;

import org.daisy.maven.xproc.api.XProcEngine;
import org.daisy.maven.xproc.api.XProcExecutionException;

import org.xml.sax.InputSource;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;

@Component(
	name = "org.daisy.maven.xproc.calabash.Calabash",
	service = { XProcEngine.class }
)
public class Calabash implements XProcEngine {

	private URIResolver nextURIResolver = null;
	private String nextCatalogFile = null;
	private XdmNode nextConfig = null;
	private XdmNode nextDefaultConfig = null;

	@Reference(
		name = "URIResolver",
		unbind = "-",
		service = URIResolver.class,
		cardinality = ReferenceCardinality.OPTIONAL,
		policy = ReferencePolicy.STATIC
	)
	protected void setURIResolver(URIResolver uriResolver) {
		nextURIResolver = uriResolver;
	}

	public void setCatalog(URL catalogFile) {
		if (catalogFile != null)
			nextCatalogFile = catalogFile.toString();
		else
			nextCatalogFile = null;
	}

	public void setCatalog(File catalogFile) {
		if (catalogFile != null && catalogFile.exists())
			nextCatalogFile = catalogFile.getPath();
		else
			nextCatalogFile = null;
	}

	// Settings from a custom calabash.xml
	public void setConfiguration(File configFile) {
		if (configFile == null)
			nextConfig = null;
		else
			try {
				XProcConfiguration config = new XProcConfiguration("he", false);
				nextConfig = config.getProcessor().newDocumentBuilder()
					.build(new SAXSource(new InputSource(new FileReader(configFile)))); }
			catch (FileNotFoundException e) {
				throw new IllegalArgumentException("Config file does not exist", e); }
			catch (SaxonApiException e) {
					throw new RuntimeException(e); }
	}

	// Settings to be always applied
	public void setDefaultConfiguration(Reader defaultConfig) {
		XProcConfiguration config = new XProcConfiguration("he", false);
		try {
			nextDefaultConfig = config.getProcessor().newDocumentBuilder()
				.build(new SAXSource(new InputSource(defaultConfig))); }
		catch (SaxonApiException e) {
			throw new RuntimeException(e); }
	}

	private XProcRuntime currentRuntime = null;
	private URIResolver currentURIResolver = null;
	private String currentCatalogFile = null;
	private XdmNode currentConfig = null;
	private XdmNode currentDefaultConfig = null;

	private XProcRuntime runtime() {

		// A new runtime needs to be created for every run because of
		// a bug in XMLCalabash with p:iteration-position().
		currentRuntime = null;
		currentURIResolver = null;
		currentCatalogFile = null;
		currentConfig = null;
		currentDefaultConfig = null;

		System.setProperty("com.xmlcalabash.config.user", "false");
		System.setProperty("com.xmlcalabash.config.local", "false");
		if (currentRuntime == null || !equal(nextConfig, currentConfig) || !equal(nextDefaultConfig, currentDefaultConfig)) {
			XProcConfiguration config = new XProcConfiguration("he", false);
			if (nextDefaultConfig != null)
				config.parse(nextDefaultConfig);
			if (nextConfig != null)
				config.parse(nextConfig);
			currentRuntime = new XProcRuntime(config); }
		if (nextURIResolver == null)
			nextURIResolver = simpleURIResolver();
		if (!equal(nextCatalogFile, currentCatalogFile) || nextURIResolver != currentURIResolver) {
			if (nextCatalogFile != null) {
				CatalogManager catalogManager = new CatalogManager();
				// catalogManager.debug.setDebug(5);
				catalogManager.setUseStaticCatalog(false);
				catalogManager.setCatalogFiles(nextCatalogFile);
				currentRuntime.setURIResolver(fallingBackURIResolver(jarURIResolver(), nextURIResolver, new CatalogResolver(catalogManager))); }
			else
				currentRuntime.setURIResolver(fallingBackURIResolver(jarURIResolver(), nextURIResolver)); }
		currentURIResolver = nextURIResolver;
		currentCatalogFile = nextCatalogFile;
		currentConfig = nextConfig;
		currentDefaultConfig = nextDefaultConfig;
		return currentRuntime;
	}

	public void run(String pipeline,
	                Map<String,List<String>> inputs,
	                Map<String,String> outputs,
	                Map<String,String> options,
	                Map<String,Map<String,String>> parameters)
			throws XProcExecutionException {
		run(pipeline, inputs, outputs, options, parameters, null);
	}

	public void run(String pipeline,
	                Map<String,List<String>> inputs,
	                Map<String,String> outputs,
	                Map<String,String> options,
	                Map<String,Map<String,String>> parameters,
	                Map<String,?> context)
			throws XProcExecutionException {
		XProcRuntime runtime = runtime();
		try {
			XPipeline xpipeline = runtime.load(new Input(pipeline));
			if (inputs != null)
				for (String port : inputs.keySet())
					for (String document : inputs.get(port))
						xpipeline.writeTo(port, runtime.parse(document, null));
			if (options != null)
				for (String name : options.keySet())
					xpipeline.passOption(new QName("", name), new RuntimeValue(options.get(name)));
			if (parameters != null)
				for (String port : parameters.keySet())
					for (String name : parameters.get(port).keySet())
						xpipeline.setParameter(port, new QName("", name), new RuntimeValue(parameters.get(port).get(name)));
			xpipeline.run();
			if (outputs != null)
				for (String port : xpipeline.getOutputs())
					if (outputs.containsKey(port)) {
						String outFile = new URI(outputs.get(port)).getPath();
						new File(outFile).getParentFile().mkdirs();
						WritableDocument wdoc = new WritableDocument(
							runtime,
							outFile,
							xpipeline.getSerialization(port),
							new FileOutputStream(outFile));
						ReadablePipe rpipe = xpipeline.readFrom(port);
						while (rpipe.moreDocuments())
							wdoc.write(rpipe.read()); }}
		catch (Exception e) {
			throw new XProcExecutionException("Calabash failed to execute XProc", e); }
	}

	private static URIResolver simpleURIResolver() {
		return new URIResolver() {
			public Source resolve(String href, String base) throws TransformerException {
				if (href.startsWith("http:"))
					return null;
				try {
					URI uri;
					if (base != null)
						uri = new URI(base).resolve(new URI(href));
					else
						uri = new URI(href);
					return new SAXSource(new InputSource(uri.toASCIIString())); }
				catch (URISyntaxException e) {
					throw new TransformerException(e); }
			}
		};
	}

	private static URIResolver jarURIResolver() {
		return new URIResolver() {
			public Source resolve(String href, String base) throws TransformerException {
				try {
					if (!href.startsWith("http:") && base != null && base.startsWith("jar:file:"))
						return new SAXSource(new InputSource(new URL(new URL(base), href).toString())); }
				catch (MalformedURLException e) {}
				return null;
			}
		};
	}

	private static URIResolver fallingBackURIResolver(final URIResolver... resolvers) {
		return new URIResolver() {
			public Source resolve(String href, String base) throws TransformerException {
				Source source = null;
				Iterator<URIResolver> iterator = Iterators.forArray(resolvers);
				while (iterator.hasNext()) {
					source = iterator.next().resolve(href, base);
					if (source != null)
						break; }
				return source;
			}
		};
	}
}


/*
 * Copyright (C) 2013,2014 The Cat Hive Developers.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cathive.fx.inject.core;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javafx.util.Builder;
import javafx.util.StringConverter;

/**
 * Abstract base class for all component builders that use
 * dependency injection framework to construct instances.
 * <p>
 * Currently, the logic to find appropriate setter methods a and look up the
 * StringConverters in a Map seems a duplicate of what has already been implemented
 * in the JavaFX runtime.
 * A better solution may follow in the future.
 *
 * @param <T> Type of the class to be constructed.
 *
 * @author Benjamin P. Jung
 * @since 1.1.0
 */
public abstract class FXMLComponentBuilder<T> extends AbstractMap<String, Object> implements Builder<T> {

    private final Class<T> componentClass;

    private final Map<String, Object> componentProperties = new HashMap<>();

    /**
     * Constructs a new component builder for the given class.
     * @param componentClass
     *         Class to be used when constructing new instances.
     */
    protected FXMLComponentBuilder(final Class<T> componentClass) {
        super();
        this.componentClass = componentClass;
    }

    @Override
    public Object put(final String key, final Object value) {
        componentProperties.put(key, value);
        return null;
    }

    @Override
    public Set<Map.Entry<String, Object>> entrySet() {
        throw new UnsupportedOperationException();
    }

    @Override
    public T build() {
        final T component = getInstance(this.componentClass);
        for (final String key : componentProperties.keySet()) {
            final Object value = componentProperties.get(key);
            final String setterName = String.format("set%s%s", key.substring(0, 1).toUpperCase(), key.substring(1));
            try {
                Method setterMethod = null;
                for (Method method : componentClass.getMethods()) {
                    if (method.getName().equals(setterName)) {
                        setterMethod = method;
                        break;
                    }
                }
                if (setterMethod == null) {
                    throw new IllegalStateException(String.format("No setter for field '%s' could be found.", key));
                }
                final Class<?> paramType = setterMethod.getParameterTypes()[0];
                Object paramValue;
                if (Enum.class.isAssignableFrom(paramType)) {
                    paramValue = paramType.getMethod("valueOf", String.class).invoke(setterMethod, value);
                } else {
                    final StringConverter<?> stringConverter = getStringConverter(paramType);
                    paramValue = stringConverter.fromString((String) value);
                }
                setterMethod.invoke(component, paramValue);
            } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }
        return component;
    }

    /**
     * Returns an instance of the requested class from the dependency injection framework being used.
     *
     * @param clazz Class to be constructed via DI container.
     * @return An instance of the requested class that has been fetched
     * via the concrete implementation of DI container being used.
     */
    protected abstract T getInstance(Class<T> clazz);

    /**
     * Retrieves a {@link javafx.util.StringConverter} instance for the given class.
     * @param valueClass
     *         Class to be used when looking for a matching string converter.
     * @return
     *         A string converter that can handle values of the given class.
     */
    private StringConverter<?> getStringConverter(final Class<?> valueClass) {
        Class<? extends StringConverter<?>> aClass = StringConverterRetriever.retrieveConverterFor(valueClass);
        if (aClass == null) {
            throw new IllegalArgumentException(String.format("Can't find StringConverter for class '%s'.", valueClass.getName()));
        }
        try {
            return aClass.newInstance();
        } catch (final InstantiationException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
    }

}


/*
 * Copyright (C) 2013,2014 The Cat Hive Developers.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cathive.fx.cdi;

import com.cathive.fx.inject.core.FXMLLoaderParams;
import javafx.fxml.FXMLLoader;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.InjectionPoint;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ResourceBundle;

import static com.cathive.fx.cdi.CdiFXMLLoader.*;

/**
 * This factory is responsible for the production of CDI-aware {@link javafx.fxml.FXMLLoader} instances.
 *
 * @author Benjamin P. Jung
 */
@ApplicationScoped
class CdiFXMLLoaderFactory {

    /**
     * Create a CDI-aware FXMLLoader.
     * If an annotation of type @FXMLLoaderParams can be found, use it's parameters
     * to configure the FXMLLoader instance that shall be used to perform the loading
     * of the FXML file.
     *
     * @param injectionPoint
     *     Injection point.
     * @return
     *     A new FXMLLoader instance.
     */
    @Produces
    @FXMLLoaderParams
    FXMLLoader createCdiFXMLLoader(final InjectionPoint injectionPoint) {
        final CdiFXMLLoader fxmlLoader = new CdiFXMLLoader();
        final Annotated annotated = injectionPoint.getAnnotated();
        final Class<?> declaringClass = injectionPoint.getMember().getDeclaringClass();
        if (annotated.isAnnotationPresent(FXMLLoaderParams.class)) {
            final FXMLLoaderParams annotation = annotated.getAnnotation(FXMLLoaderParams.class);
            initializeFXMLLoader(fxmlLoader, declaringClass, annotation.location(), annotation.resources(), annotation.charset());
        }
        return fxmlLoader;
    }

    /**
     * Initializes the given FXMLLoader instance using the provided parameters.
     *
     * @param fxmlLoader  never null
     * @param targetClass never null
     * @param location    never null
     * @param resources   never null
     * @param charset     never null
     */
    static void initializeFXMLLoader(final FXMLLoader fxmlLoader, final Class<?> targetClass, final String location, final String resources, final String charset) {

        checkAndSetLocation(fxmlLoader, targetClass, location);
        if (charset != null && !charset.equals(CHARSET_UNSPECIFIED)) {
            fxmlLoader.setCharset(Charset.forName(charset));
        }
        if (resources != null && !resources.equals(RESOURCES_UNSPECIFIED)) {
            fxmlLoader.setResources(ResourceBundle.getBundle(resources));
        }

    }

    /**
     * Checks the location that has been specified (if any) and uses the default
     * class loader to create an URL that points to a FXML file on the classpath.
     *
     * @param fxmlLoader  never null
     * @param targetClass never null
     * @param location    never null and should point to an existing FXML file, an Exception is thrown otherwise
     */
    private static void checkAndSetLocation(FXMLLoader fxmlLoader, Class<?> targetClass, String location) {
        if (location != null && !location.equals(LOCATION_UNSPECIFIED)) {
            final URL locationUrl = targetClass.getResource(location);
            if (locationUrl == null) {
                throw new IllegalArgumentException(String.format("Couldn't find FXML file: \"%s\".", location));
            }
            fxmlLoader.setLocation(locationUrl);
        }
    }

}


package com.github.kmbulebu.nicknack.server.web;

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.EntityLinks;
import org.springframework.hateoas.ExposesResourceFor;
import org.springframework.hateoas.RelProvider;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.github.kmbulebu.nicknack.core.attributes.AttributeDefinition;
import com.github.kmbulebu.nicknack.core.events.EventDefinition;
import com.github.kmbulebu.nicknack.server.Application;
import com.github.kmbulebu.nicknack.server.model.AttributeDefinitionResource;
import com.github.kmbulebu.nicknack.server.model.EventDefinitionResource;
import com.github.kmbulebu.nicknack.server.services.EventDefinitionService;
import com.github.kmbulebu.nicknack.server.services.exceptions.AttributeDefinitionNotFoundException;
import com.github.kmbulebu.nicknack.server.services.exceptions.EventDefinitionNotFoundException;
import com.github.kmbulebu.nicknack.server.services.exceptions.ProviderNotFoundException;

@RestController
@RequestMapping(value="/api/eventDefinitions", produces={"application/hal+json"})
@ExposesResourceFor(EventDefinitionResource.class)
public class EventDefinitionsController {

	private static final Logger LOG = LogManager.getLogger(Application.APP_LOGGER_NAME);

	@Autowired
	private EventDefinitionService eventDefinitionService;

	@Autowired
	private RelProvider relProvider;

	@Autowired
	private EntityLinks entityLinks;

	// TODO Refactor HATEOAS link building. Time for ResourceAssembler or moving this stuff up the service. Although moving it up will create a circular dep.

	@RequestMapping(value="", method={RequestMethod.GET, RequestMethod.HEAD})
	public Resources<EventDefinitionResource> getEventDefinitions() throws EventDefinitionNotFoundException, ProviderNotFoundException, AttributeDefinitionNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry();
		}

		final Resources<EventDefinitionResource> resources = getEventDefinitions(eventDefinitionService.getEventDefinitions());

		if (LOG.isTraceEnabled()) {
			LOG.exit(resources);
		}
		return resources;
	}

	@RequestMapping(value="", params="provider", method={RequestMethod.GET, RequestMethod.HEAD})
	public Resources<EventDefinitionResource> getEventDefinitions(@RequestParam UUID provider) throws EventDefinitionNotFoundException, ProviderNotFoundException, AttributeDefinitionNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry();
		}

		final Resources<EventDefinitionResource> resources = getEventDefinitions(eventDefinitionService.getEventDefinitionsByProvider(provider));

		if (LOG.isTraceEnabled()) {
			LOG.exit(resources);
		}
		return resources;
	}

	private Resources<EventDefinitionResource> getEventDefinitions(Collection<EventDefinition> eventDefinitions) throws EventDefinitionNotFoundException, ProviderNotFoundException, AttributeDefinitionNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(eventDefinitions);
		}

		final List<EventDefinitionResource> eventDefinitionResources = new ArrayList<EventDefinitionResource>(eventDefinitions.size());

		for (EventDefinition eventDefinition : eventDefinitions) {
			final EventDefinitionResource resource = new EventDefinitionResource(eventDefinition);
			resource.add(linkTo(methodOn(EventDefinitionsController.class).getEventDefinition(eventDefinition.getUUID())).withSelfRel());
			resource.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinitions(eventDefinition.getUUID())).withRel("attributeDefinitions"));
			eventDefinitionResources.add(resource);
		}

		final Resources<EventDefinitionResource> resources = new Resources<EventDefinitionResource>(eventDefinitionResources);
		resources.add(entityLinks.linkToCollectionResource(EventDefinitionResource.class));

		if (LOG.isTraceEnabled()) {
			LOG.exit(resources);
		}
		return resources;
	}

	@RequestMapping(value="/{uuid}", method={RequestMethod.GET, RequestMethod.HEAD})
	public EventDefinitionResource getEventDefinition(@PathVariable UUID uuid) throws EventDefinitionNotFoundException, ProviderNotFoundException, AttributeDefinitionNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(uuid);
		}

		final EventDefinition eventDefinition = eventDefinitionService.getEventDefinition(uuid);
		final EventDefinitionResource resource = new EventDefinitionResource(eventDefinition);
		resource.add(linkTo(methodOn(EventDefinitionsController.class).getEventDefinition(eventDefinition.getUUID())).withSelfRel());
		resource.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinitions(uuid)).withRel("attributeDefinitions"));

		if (LOG.isTraceEnabled()) {
			LOG.exit(resource);
		}
		return resource;
	}

	@RequestMapping(value="/{eventUuid}/attributeDefinitions", method={RequestMethod.GET, RequestMethod.HEAD})
	public Resources<AttributeDefinitionResource> getAttributeDefinitions(@PathVariable UUID eventUuid) throws EventDefinitionNotFoundException, ProviderNotFoundException, AttributeDefinitionNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(eventUuid);
		}

		final List<AttributeDefinition> attributeDefinitions = eventDefinitionService.getAttributeDefinitions(eventUuid);
		final List<AttributeDefinitionResource> attributeDefinitionResources = new ArrayList<AttributeDefinitionResource>(attributeDefinitions.size());

		for (AttributeDefinition attributeDefinition : attributeDefinitions) {
			final AttributeDefinitionResource resource = new AttributeDefinitionResource(attributeDefinition);
			resource.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinition(eventUuid, attributeDefinition.getUUID())).withSelfRel());

			attributeDefinitionResources.add(resource);
		}

		final Resources<AttributeDefinitionResource> resources = new Resources<AttributeDefinitionResource>(attributeDefinitionResources);
		resources.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinitions(eventUuid)).withSelfRel());

		if (LOG.isTraceEnabled()) {
			LOG.exit(resources);
		}
		return resources;
	}

	@RequestMapping(value="/{eventUuid}/attributeDefinitions/{uuid}", method={RequestMethod.GET, RequestMethod.HEAD})
	public AttributeDefinitionResource getAttributeDefinition(@PathVariable UUID eventUuid, @PathVariable UUID uuid) throws EventDefinitionNotFoundException, ProviderNotFoundException, AttributeDefinitionNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(eventUuid, uuid);
		}

		final AttributeDefinition attributeDefinition = eventDefinitionService.getAttributeDefinition(eventUuid, uuid);

		final AttributeDefinitionResource resource = new AttributeDefinitionResource(attributeDefinition);
		resource.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinition(eventUuid, attributeDefinition.getUUID())).withSelfRel());
		resource.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinitionValues(eventUuid, attributeDefinition.getUUID())).withRel("values"));

		if (LOG.isTraceEnabled()) {
			LOG.exit(resource);
		}
		return resource;
	}

	@RequestMapping(value="/{eventUuid}/attributeDefinitions/{uuid}/values", method={RequestMethod.GET, RequestMethod.HEAD})
	public ResponseEntity<Resource<Map<String, String>>> getAttributeDefinitionValues(@PathVariable UUID eventUuid, @PathVariable UUID uuid) throws EventDefinitionNotFoundException, ProviderNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(eventUuid, uuid);
		}

		final Map<String, String> attributeDefinitionValues = eventDefinitionService.getAttributeDefinitionValues(eventUuid, uuid);

		ResponseEntity<Resource<Map<String, String>>> response;
		if (attributeDefinitionValues == null) {
			response = new ResponseEntity<>(HttpStatus.NOT_FOUND);
		} else {
			final Resource<Map<String, String>> resource = new Resource<Map<String, String>>(attributeDefinitionValues);
			resource.add(linkTo(methodOn(EventDefinitionsController.class).getAttributeDefinitionValues(eventUuid, uuid)).withSelfRel());
			response = new ResponseEntity<>(resource, HttpStatus.OK);
		}

		if (LOG.isTraceEnabled()) {
			LOG.exit(response);
		}
		return response;
	}

}


package com.bytebybyte.google.geocoding.service.request;

import java.util.LinkedHashMap;
import java.util.Map;

import com.bytebybyte.google.geocoding.service.response.LocationType;
import com.bytebybyte.google.geocoding.service.response.Type;

public class ReverseGeocodeRequestBuilder {

	protected Map<String, String> parameters = new LinkedHashMap<String, String>();

	public ReverseGeocodeRequestBuilder() {
	}

	/**
	 * Your 'free' application's API key. This key identifies your application
	 * for purposes of quota management.
	 *
	 * @param key
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder key(String key) {
		parameters.put("key", key);
		return this;
	}

	/**
	 * Your 'business' application's API key. This key identifies your
	 * application for purposes of quota management.
	 *
	 * @param client
	 * @param signature
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder key(String client, String signature) {
		parameters.put("client", client);
		parameters.put("signature", signature);
		return this;
	}

	/**
	 * Output format.
	 *
	 * - json (recommended) indicates output in JavaScript Object Notation.
	 *
	 * - xml indicates output as XML
	 *
	 * @param output
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder output(String output) {
		parameters.put("output", output);
		return this;
	}

	/**
	 * The location latitude and longitude.
	 *
	 * This parameter is required.
	 *
	 * @param lat
	 * @param lng
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder latlng(Double lat, Double lng) {
		parameters.put("latlng", lat + "," + lng);
		return this;
	}

	/**
	 * The language in which to return results. If language is not supplied, the
	 * geocoder will attempt to use the native language of the domain from which
	 * the request is sent wherever possible.
	 *
	 * @param language
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder language(String language) {
		parameters.put("language", language);
		return this;
	}

	/**
	 * One or more address types, separated by a pipe (|).
	 *
	 * Examples of address types: country, street_address, postal_code.
	 *
	 * For a full list of allowable values, see the address types on this page.
	 * Specifying a type will restrict the results to this type. If multiple
	 * types are specified, the API will return all addresses that match any
	 * of the types. Note: This parameter is available only for requests that
	 * include an API key or a client ID.
	 *
	 * @param types
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder resultType(Type[] types) {
		if (types == null || types.length == 0)
			return this;

		StringBuffer resultType = new StringBuffer();
		for (int i = 0; i < types.length - 1; i++)
			resultType.append(types[i] + "|");
		resultType.append(types[types.length - 1]);

		parameters.put("result_type", resultType.toString());
		return this;
	}

	/**
	 * One or more location types, separated by a pipe (|).
	 *
	 * Specifying a type will restrict the results to this type. If multiple
	 * types are specified, the API will return all addresses that match any
	 * of the types.
	 *
	 * Note: This parameter is available only for requests that include an API
	 * key or a client ID.
	 *
	 * The following values are supported:
	 *
	 *   "ROOFTOP" restricts the results to addresses for which we have
	 *   location information accurate down to street address precision.
	 *
	 *   "RANGE_INTERPOLATED" restricts the results to those that reflect
	 *   an approximation (usually on a road) interpolated between two precise
	 *   points (such as intersections). An interpolated range generally
	 *   indicates that rooftop geocodes are unavailable for a street address.
	 *
	 *   "GEOMETRIC_CENTER" restricts the results to geometric centers of a
	 *   location such as a polyline (for example, a street) or polygon (region).
	 *
	 *   "APPROXIMATE" restricts the results to those that are characterized
	 *   as approximate.
	 *
	 * @param types
	 * @return ReverseGeocodeRequestBuilder
	 */
	public ReverseGeocodeRequestBuilder locationType(LocationType[] types) {
		if (types == null || types.length == 0)
			return this;

		StringBuffer resultType = new StringBuffer();
		for (int i = 0; i < types.length - 1; i++)
			resultType.append(types[i] + "|");
		resultType.append(types[types.length - 1]);

		parameters.put("location_type", resultType.toString());
		return this;
	}

	/**
	 * Build the request object.
	 *
	 * @return AddressRequest
	 */
	public ReverseGeocodeRequest build() {
		return new ReverseGeocodeRequest(parameters);
	}

}


package com.netflix.config.sources;

import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import com.netflix.config.PollResult;
import com.netflix.config.PolledConfigurationSource;
import com.rackspacecloud.client.service_registry.objects.ConfigurationValue;
import com.rackspacecloud.client.service_registry.objects.Service;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.*;

public class ServiceRegistryConfigurationProvider implements PolledConfigurationSource {

    private static Logger logger = LoggerFactory.getLogger(ServiceRegistryConfigurationProvider.class);

    private static final String DELIMITER =".";
    public static final String PREFIX = "serverset";
    public static final String INTEREST = PREFIX + DELIMITER + "interest";
    private static final String SEPARATOR = ",";
    private static final String SUFFIX = "addresses";

    public static final DynamicStringProperty dynamicServiceTags = DynamicPropertyFactory.getInstance().getStringProperty(INTEREST, "");

    private final ServiceRegistryClient client;

    public ServiceRegistryConfigurationProvider(ServiceRegistryClient client) {
        this.client = client;
    }

    @Override
    public PollResult poll(boolean initial, Object checkPoint)
            throws Exception {

        Map<String, Object> map = new HashMap<String, Object>();
        for (ConfigurationValue value : client.getConfiguration()) {
            map.put(value.getId(), value.getValue());
        }

        // Do a query to get all the service tags we're interested in,
        // once we have that we'll namespace the parameters
        String tags = dynamicServiceTags.get();
        if (!tags.isEmpty()) {
            Set<String> serviceTags = new HashSet<String>(Arrays.asList(tags.split(SEPARATOR)));
            for (String tag: serviceTags) {
                Set<InetSocketAddress> pairs = new HashSet<InetSocketAddress>();
                String key = PREFIX + DELIMITER + tag + DELIMITER + SUFFIX;

                for (Service service : client.getServices(tag)) {
                    InetSocketAddress pair = getHostPortPair(service);

                    if (pair != null) {
                        pairs.add(pair);
                    }
                }

                if (!pairs.isEmpty()) {
                    map.put(key, StringUtils.join(pairs, SEPARATOR));
                }
            }
        }
        return PollResult.createFull(map);
    }

    @Override
    public String toString() {
        return "ServiceRegistryConfigurationProvider [client=" + client.toString() + "]";
    }

    /**
     * Safely get the information from our convention
     * @param svc
     * @return
     */
    public static InetSocketAddress getHostPortPair(Service svc) {
        try {
            return new InetSocketAddress(svc.getMetadata().get("service.host"),
                    Integer.parseInt(svc.getMetadata().get("service.port")));
        } catch (Exception e) {
            logger.error("Exception extracting metadata from service instance {}", svc, e);
            return null;
        }
    }

    public static Service setHostPortPair(String host, int port, Service svc) {
        svc.getMetadata().put("service.host", host);
        svc.getMetadata().put("service.port", String.valueOf(port));
        return svc;
    }
}


package com.github.kmbulebu.nicknack.core.attributes.filters;

import java.text.ParseException;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.github.kmbulebu.nicknack.core.attributes.AttributeCollection;
import com.github.kmbulebu.nicknack.core.attributes.AttributeDefinition;
import com.github.kmbulebu.nicknack.core.units.Unit;

/**
 * Evaluates of a collection of AttributeFilterExpressions matches
 * a collection of attributes.
 */
public class AttrbuteFilterExpressionCollectionEvaluator {

	private static final Logger LOG = LogManager.getLogger();

	/**
	 *
	 * @param filterCollection
	 * @param attributeCollection
	 * @return True if all attribute filters match. False, if the event is not applicable to the filter, or at least one attribute filter does not match.
	 * @throws ParseException
	 */

	public boolean evaluate(AttributeFilterExpressionCollection filterCollection, AttributeCollection attributeCollection, List<AttributeDefinition> attributeDefinitions) throws ParseException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(filterCollection, attributeCollection);
		}

		// All attribute filters have to match.
		for (AttributeFilterExpression expression : filterCollection.getAttributeFilterExpressions()) {
			final UUID attributeDefinitionUuid = expression.getAttributeDefinitionUuid();
			if (!evaluate(attributeDefinitionUuid, expression, attributeCollection.getAttributes(), attributeDefinitions)) {
				if (LOG.isTraceEnabled()) {
					LOG.exit(false);
				}
				return false;
			}
		}

		// They all matched.
		if (LOG.isTraceEnabled()) {
			LOG.exit(true);
		}
		return true;
	}

	// Find an attribute definition that applies to a particular attribute filter.
	protected AttributeDefinition getApplicableAttributeDefinition(final UUID attributeDefinitionUuid, final List<AttributeDefinition> attributeDefinitions) {
		if (LOG.isTraceEnabled()) {
			LOG.entry(attributeDefinitionUuid, attributeDefinitions);
		}
		AttributeDefinition attributeDefinition = null;
		for (AttributeDefinition anAttributeDefinition : attributeDefinitions) {
			if (anAttributeDefinition.getUUID().equals(attributeDefinitionUuid)) {
				attributeDefinition = anAttributeDefinition;
				break;
			}
		}
		if (LOG.isTraceEnabled()) {
			LOG.exit(attributeDefinition);
		}
		return attributeDefinition;
	}

	// Evaluate single attribute filter
	protected boolean evaluate(final UUID attributeDefinitionUuid, final AttributeFilterExpression attributeFilter, final Map<UUID, String> eventAttributes, final List<AttributeDefinition> attributeDefinitions) throws ParseException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(attributeDefinitionUuid, attributeFilter, eventAttributes, attributeDefinitions);
		}
		// Find a matching attribute
		final String attributeValue = eventAttributes.get(attributeDefinitionUuid);
		if (attributeValue == null) {
			// No attribute value to match attribute filter.
			if (LOG.isTraceEnabled()) {
				LOG.trace("An attributeValue was not specified for this attribute definition.");
				LOG.exit(false);
			}
			return false;
		}

		// Find the Attribute definition that matches our filter.
		final AttributeDefinition attributeDefinition = getApplicableAttributeDefinition(attributeDefinitionUuid, attributeDefinitions);

		if (attributeDefinition == null) {
			// Really shouldn't have any filters defined for attributes that don't exist.
			if (LOG.isTraceEnabled()) {
				LOG.trace("The attributeDefinition did not exist.");
				LOG.exit(false);
			}
			return false;
		}

		final Unit unit = attributeDefinition.getUnits();
		try {
			boolean result = unit.evaluate(attributeFilter.getOperator(), attributeValue, attributeFilter.getOperand());
			if (LOG.isTraceEnabled()) {
				LOG.exit(result);
			}
			return result;
		} catch (ParseException e) {
			if (LOG.isTraceEnabled()) {
				LOG.throwing(e);
			}
			throw e;
		}
	}

}


package com.github.kmbulebu.nicknack.server.services.impl;

import java.text.ParseException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import rx.Observable;
import rx.Subscription;
import rx.functions.Action1;

import com.github.kmbulebu.nicknack.core.actions.Action;
import com.github.kmbulebu.nicknack.core.attributes.AttributeDefinition;
import com.github.kmbulebu.nicknack.core.events.Event;
import com.github.kmbulebu.nicknack.core.events.filters.EventFilter;
import com.github.kmbulebu.nicknack.core.events.filters.EventFilterEvaluator;
import com.github.kmbulebu.nicknack.core.providers.Provider;
import com.github.kmbulebu.nicknack.core.providers.ProviderService;
import com.github.kmbulebu.nicknack.core.states.State;
import com.github.kmbulebu.nicknack.core.states.filters.StateFilter;
import com.github.kmbulebu.nicknack.core.states.filters.StateFilterEvaluator;
import com.github.kmbulebu.nicknack.server.Application;
import com.github.kmbulebu.nicknack.server.model.ActionResource;
import com.github.kmbulebu.nicknack.server.model.EventFilterResource;
import com.github.kmbulebu.nicknack.server.model.PlanResource;
import com.github.kmbulebu.nicknack.server.model.StateFilterResource;
import com.github.kmbulebu.nicknack.server.services.ActionQueueService;
import com.github.kmbulebu.nicknack.server.services.ActionsService;
import com.github.kmbulebu.nicknack.server.services.EventFiltersService;
import com.github.kmbulebu.nicknack.server.services.PlansService;
import com.github.kmbulebu.nicknack.server.services.StateFiltersService;
import com.github.kmbulebu.nicknack.server.services.exceptions.PlanNotFoundException;

@Service
public class PlansEvaluatorServiceImpl implements Action1<Event> {

	private static final Logger LOG = LogManager.getLogger(Application.APP_LOGGER_NAME);

	@Autowired
	private ProviderService providerService;

	@Autowired
	private PlansService plansService;

	@Autowired
	private EventFiltersService eventFiltersService;

	@Autowired
	private StateFiltersService stateFiltersService;

	@Autowired
	private ActionsService actionsService;

	@Autowired
	private ActionQueueService actionQueueService;

	private Subscription eventsSubscription;

	private EventFilterEvaluator eventFilterEvaluator = new EventFilterEvaluator();

	private StateFilterEvaluator stateFilterEvaluator = new StateFilterEvaluator();

	@Autowired
	private NickNackServerProviderImpl nickNackServerProvider;

	@PostConstruct
	public void init() {
		if (LOG.isTraceEnabled()) {
			LOG.entry();
		}

		final Observable<Event> events = providerService.getEvents();
		eventsSubscription = events.subscribe(this);

		if (LOG.isTraceEnabled()) {
			LOG.exit();
		}
	}

	@PreDestroy
	public void shutdown() {
		if (LOG.isTraceEnabled()) {
			LOG.entry();
		}

		if (eventsSubscription != null) {
			eventsSubscription.unsubscribe();
		}

		if (LOG.isTraceEnabled()) {
			LOG.exit();
		}
	}

	@Override
	public void call(Event event) {
		if (LOG.isTraceEnabled()) {
			LOG.entry(event);
		}

		// TODO Do a more narrow lookup of plans that match the eventDefinition.
		final List<PlanResource> plans = plansService.getPlans();

		for (PlanResource plan : plans) {
			try {
				evaluate(plan, event);
			} catch (PlanNotFoundException e) {
				LOG.error("Could not evaluate event against plan. " + e.getMessage(), e);
			}
		}

		if (LOG.isTraceEnabled()) {
			LOG.exit();
		}
	}

	public void evaluate(PlanResource plan, Event event) throws PlanNotFoundException {
		if (LOG.isTraceEnabled()) {
			LOG.entry(plan, event);
		}

		boolean eventMatch = false;

		final Iterator<EventFilterResource> iterator = eventFiltersService.getEventFilters(plan.getUUID()).iterator();

		// If any event filter matches, then this plan is match.
		while (!eventMatch && iterator.hasNext()) {
			final EventFilter filter = iterator.next();

			try {
				eventMatch = eventFilterEvaluator.evaluate(filter, event);
			} catch (ParseException e) {
				LOG.warn("Error parsing some text while evalutaing an event filter. " + e.getMessage(), e);
				// TODO Generate an error event
				eventMatch = false;
			}

			if (LOG.isInfoEnabled() && eventMatch) {
				LOG.info("EventFilter matched: " + ((EventFilterResource) filter).getUuid());
			}
		}

		boolean stateMatch = false;
		if (eventMatch) {// Only test state if event matches
			final Iterator<StateFilterResource> stateFilterIterator = stateFiltersService.getStateFilters(plan.getUUID()).iterator();

			if (stateFilterIterator.hasNext()) {
				// If any state filter matches, then this plan is match.
				while (!stateMatch && stateFilterIterator.hasNext()) {
					final StateFilter filter = stateFilterIterator.next();

					final Provider provider = providerService.getProviderByStateDefinitionUuid(filter.getAppliesToStateDefinition());

					if (provider != null) {
						// FIXME getStates could be slow as the provider looks up the possible states.
						final List<? extends State> states = provider.getStates(filter.getAppliesToStateDefinition());

						if (states != null) {
							final Iterator<? extends State> stateIterator = states.iterator();

							while (!stateMatch && stateIterator.hasNext()) {
								final State state = stateIterator.next();
								try {
									stateMatch = stateFilterEvaluator.evaluate(filter, state);
								} catch (ParseException e) {
									LOG.warn("Error parsing some text while evalutaing an state filter. " + e.getMessage(), e);
									// TODO Generate an error state
									stateMatch = false;
								}
							} // State loop
						} // If states != null
					} // If provider != null

					if (LOG.isInfoEnabled() && stateMatch) {
						LOG.info("StateFilter matched: " + ((StateFilterResource) filter).getUuid());
					}
				} // Loop state filters
			} else {
				// State filters are not required.
				stateMatch = true;
			}
		}

		if (eventMatch && stateMatch) {
			LOG.info("Plan " + plan.getUUID() + " matches event " + event);
			for (Action action : actionsService.getActionsByPlan(plan.getUUID())) {
				LOG.info("Performing action " + action);
				final Action processedAction = processVariables(action, event);
				// TODO Group all actions together into a composite action so that they run serially, not in parallel.

				actionQueueService.enqueueAction(processedAction);
			}
		}

		if (LOG.isTraceEnabled()) {
			LOG.exit();
		}

	}

	// TODO I'd like to push a lot of this down into NickNack-core.

	protected Action processVariables(Action origAction, Event cause) {
		final ActionResource newAction = new ActionResource();
		final Map<UUID, String> newParameters = new HashMap<>();
		newAction.setAppliesToActionDefinition(origAction.getAppliesToActionDefinition());

		for (UUID key : origAction.getAttributes().keySet()) {
			newParameters.put(key,  processVariables(origAction.getAttributes().get(key), cause));
		}
		newAction.setParameters(newParameters);
		return newAction;
	}

	protected String processVariables(String value, Event cause) {
		// Build value map
		final Map<String, String> valueMap = new HashMap<>();
		final Map<UUID, AttributeDefinition> attributeMap = new HashMap<>();
		for (AttributeDefinition def : cause.getEventDefinition().getAttributeDefinitions()) {
			attributeMap.put(def.getUUID(), def);
		}
		for (UUID attributeUuid : cause.getAttributes().keySet()) {
			AttributeDefinition attribute = attributeMap.get(attributeUuid);
			valueMap.put(attribute.getName(), cause.getAttributes().get(attributeUuid));
		}
		final StrSubstitutor substitutor = new StrSubstitutor(valueMap, "{{", "}}");

		return substitutor.replace(value);
	}

}


package com.rackspacecloud.client.service_registry.curator;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.netflix.curator.framework.listen.ListenerContainer;
import com.netflix.curator.x.discovery.ServiceCache;
import com.netflix.curator.x.discovery.ServiceInstance;
import com.netflix.curator.x.discovery.details.ServiceCacheListener;
import com.rackspacecloud.client.service_registry.MethodOptions;
import com.rackspacecloud.client.service_registry.objects.Event;
import com.rackspacecloud.client.service_registry.objects.EventType;
import com.rackspacecloud.client.service_registry.objects.ServicePayload;

import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;

public class RSRServiceCacheImpl<T> implements ServiceCache<T> {

    private final RSRServiceDiscoveryImpl<T> discovery;
    private final ListenerContainer<ServiceCacheListener> listenerContainer = new ListenerContainer<ServiceCacheListener>();
    private final ConcurrentMap<String, ServiceInstance<T>> instances = Maps.newConcurrentMap();
    private final String name;

    private volatile Thread eventPoller = null;
    private volatile boolean shouldStopPolling = false;

    public RSRServiceCacheImpl(RSRServiceDiscoveryImpl<T> discovery, String name) {
        this.discovery = discovery;
        this.name = name;
    }

    //
    // ServiceCache methods (includes method of InstanceProvider<T>)
    //

    public List<ServiceInstance<T>> getInstances() {
        return Collections.unmodifiableList(Lists.newArrayList(instances.values()));
    }

    public synchronized void start() throws Exception {
        if (eventPoller != null) return;
        shouldStopPolling = false;

        eventPoller = new Thread("Event poller for " + discovery.getClient()) {
            @Override
            public void run() {
                while (!shouldStopPolling) {
                    pollAndProcessEvents();
                }
                eventPoller = null;
                shouldStopPolling = false;
            }
        };

        // backfill existing services.
        List<String> names = new ArrayList<String>();
        if (this.name != null) {
            names.add(this.name);
        } else {
            for (String name : discovery.queryForNames()) {
                names.add(name);
            }
        }
        for (String name : names) {
            for (ServiceInstance<T> instance : discovery.queryForInstances(name)) {
                instances.put(instance.getId(), instance);
            }
        }

        // start the polling thread.
        eventPoller.start();
    }

    //
    // java.io.Closeable
    //

    public synchronized void close() throws IOException {
        // again, nothing to do here.
        shouldStopPolling = true;
    }

    //
    // com.netflix.curator.framework.listen.Listenable
    //

    public void addListener(ServiceCacheListener serviceCacheListener) {
        listenerContainer.addListener(serviceCacheListener);
    }

    public void addListener(ServiceCacheListener serviceCacheListener, Executor executor) {
        listenerContainer.addListener(serviceCacheListener, executor);
    }

    public void removeListener(ServiceCacheListener serviceCacheListener) {
        listenerContainer.removeListener(serviceCacheListener);
    }

    // helpers

    private boolean isPertinent(Event e) {
        return (e.getPayload() instanceof ServicePayload)
               && ((ServicePayload)e.getPayload()).getService().getTags().contains(discovery.getType());
    }

    private String processEvents(List<Event> events) {
        String lastId = null;
        for (Event e : events) {
            lastId = e.getId();
            if (!isPertinent(e)) {
                continue;
            }
            // ideally, the dispatch happens on a separate thread.
            try {
                // listeners should do work.
                listenerContainer.forEach(new Function<ServiceCacheListener, Void>() {
                    public Void apply(@Nullable ServiceCacheListener serviceCacheListener) {
                        if (serviceCacheListener == null) return null;
                        serviceCacheListener.cacheChanged();
                        return null;
                    }
                });

                // make sure the local collection is maintained.
                final ServicePayload ee = (ServicePayload)e.getPayload();
                if (name == null || (name.equals(ee.getService().getMetadata().get("name")))) {
                    try {
                        if (e.getType() == EventType.SERVICE_JOINED) {
                            instances.put(ee.getService().getId(), discovery.convert(ee.getService()));
                        } else if (e.getType() == EventType.SERVICE_REMOVED || e.getType() == EventType.SERVICE_TIMEOUT) {
                            instances.remove(ee.getService().getId());
                        }
                    } catch (Exception fromConverter) {
                        // todo: log it.
                    }
                }
            } catch (Throwable th) {
                // bad listener! todo: log only.
            }
        }
        return lastId;
    }

    // pull a page of events, process that page, pull the next page, etc.
    // todo: switch to iterator.
    private void pollAndProcessEvents() {
        MethodOptions options = new MethodOptions(100, null);
        List<Event> events = null;
        int count = 0;
        do {
            if (shouldStopPolling) break;
            count += 1;
            try {
                // get events from server, filter the ones we are interested in.
                events = Lists.newArrayList(discovery.getClient().getEventsClient().list(options));
                String lastEventId = processEvents(events);
                options = options.withMarker(lastEventId);
            } catch (Exception ex) {
                // todo: just log it.
                events = null;
            }
        } while (events != null && events.size() > 0);

        // if it only happened once, assume there are not many events happening.
        if (count == 1) {
            // todo: trace message.
            // todo: this should become configurable.
            try { Thread.sleep(1000); } catch (Exception ex) {}
        }
    }
}