/*
 * Copyright 2007 Ralf Joachim
 * 
 * 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 org.exolab.castor.builder.types;

import org.exolab.castor.xml.schema.Facet;
import org.exolab.javasource.JSourceCode;

/**
 * A base class for types which support the digits, range, whiteSpace and pattern facets.
 * 
 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
 * @version $Revision: 6662 $ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
 * @since 1.1
 */
public abstract class AbstractDigitsFacet extends AbstractRangeFacet {
  // --------------------------------------------------------------------------

  /**
   * If set to true only '0' is allowed for the fractionDigits facet. If set to false all positive
   * values are allowed for fractionDigits facet.
   */
  private final boolean _fractionDigitsZeroOnly;

  /** Total number of digits. */
  private int _totalDigits = -1;

  /** Total number of fraction digits. */
  private int _fractionDigits = -1;

  // --------------------------------------------------------------------------

  /**
   * No-arg constructor. By default only '0' is supported for the fractionDigits facet.
   */
  protected AbstractDigitsFacet() {
    this(true);
  }

  /**
   * Construct a new AbstractDigitsFacet optionally allowing the fractionDigits facet to be set to
   * all positive values.
   *
   * @param fractionDigitsZeroOnly If set to true only '0' is allowed for the fractionDigits facet.
   *        If set to false all positive values are allowed for fractionDigits facet.
   */
  protected AbstractDigitsFacet(final boolean fractionDigitsZeroOnly) {
    _fractionDigitsZeroOnly = fractionDigitsZeroOnly;
  }

  // --------------------------------------------------------------------------

  /**
   * Returns the totalDigits facet value of this XSType.
   * 
   * @return The totalDigits facet value of this XSType.
   */
  public final int getTotalDigits() {
    return _totalDigits;
  }

  /**
   * Sets the totalDigits facet for this XSType.
   * 
   * @param totalDigits The value of totalDigits (must be >0).
   */
  public final void setTotalDigits(final int totalDigits) {
    if (totalDigits <= 0) {
      throw new IllegalArgumentException(
          getName() + ": the totalDigits facet must be positive: " + totalDigits);
    }
    _totalDigits = totalDigits;
  }

  /**
   * Returns the fractionDigits facet value of this XSType.
   * 
   * @return The fractionDigits facet value of this XSType.
   */
  public final int getFractionDigits() {
    return _fractionDigits;
  }

  /**
   * Sets the fractionDigits facet for this XSType.
   * 
   * @param fractionDigits The value of fractionDigits (must be >=0).
   */
  public final void setFractionDigits(final int fractionDigits) {
    if (fractionDigits < 0) {
      throw new IllegalArgumentException(
          getName() + ": the fractionDigits facet must be positive: " + fractionDigits);
    }
    if (_fractionDigitsZeroOnly && (fractionDigits > 0)) {
      throw new IllegalArgumentException(
          getName() + ": only '0' allowed for fractionDigits facet: " + fractionDigits);
    }
    _fractionDigits = fractionDigits;
  }

  // --------------------------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  protected final void setFacet(final Facet facet) {
    super.setFacet(facet);
    setDigitsFacet(facet);
  }

  /**
   * Transfer given facet if it is a digits facet.
   *
   * @param facet The facet to transfer.
   */
  protected final void setDigitsFacet(final Facet facet) {
    String name = facet.getName();
    if (Facet.TOTALDIGITS.equals(name)) {
      setTotalDigits(facet.toInt());
    } else if (Facet.FRACTIONDIGITS.equals(name)) {
      setFractionDigits(facet.toInt());
    }
  }

  /**
   * Generate the source code for digits facet validation.
   *
   * @param jsc The JSourceCode to fill in.
   * @param validatorName The name of the TypeValidator that the digits should be added to.
   */
  protected final void codeDigitsFacet(final JSourceCode jsc, final String validatorName) {
    // -- totalDigits
    if (getTotalDigits() != -1) {
      jsc.add("{0}.setTotalDigits({1});", validatorName, Integer.toString(getTotalDigits()));
    }

    // -- fractionDigits
    if (!_fractionDigitsZeroOnly && (getFractionDigits() != -1)) {
      jsc.add("{0}.setFractionDigits({1});", validatorName, Integer.toString(getFractionDigits()));
    }
  }

  // --------------------------------------------------------------------------
}
