/*
 * Copyright 2006 Le Duc Bao, 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.castor.ddlgen.keygenerator;

import org.castor.ddlgen.DDLWriter;
import org.castor.ddlgen.GeneratorException;
import org.castor.ddlgen.schemaobject.KeyGenerator;
import org.exolab.castor.mapping.xml.KeyGeneratorDef;
import org.exolab.castor.mapping.xml.Param;

/** 
 * SEQUENCE key generator can be used only with Oracle, PostgreSQL, Interbase and 
 * SAP DB. It generates keys using sequences.
 * 
 * @author <a href="mailto:leducbao AT gmail DOT com">Le Duc Bao</a>
 * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
 * @version $Revision: 5951 $ $Date: 2006-04-25 16:09:10 -0600 (Tue, 25 Apr 2006) $
 * @since 1.1
 */
public final class SequenceKeyGenerator extends KeyGenerator {
    //--------------------------------------------------------------------------

    /** Name of key generator algorithm. */
    public static final String ALGORITHM_NAME = "SEQUENCE";
    
    /** Parameter that defines the name or a pattern for the sequence. */
    private static final String PARAM_SEQUENCE = "sequence";
    
    /** Paramater that defines if sequence returns generated value. */
    private static final String PARAM_RETURNING = "returning";
    
    /** Parameter that defines if key is generated by a trigger. */
    private static final String PARAM_TRIGGER = "trigger";
    
    /** Parameter that defines the increment of the sequence. */
    private static final String PARAM_INCREMENT = "increment";

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

    /** The key generator factory that has created this key generator and will also be
     *  responsible to generate the DDL for the sequence. */
    private final SequenceKeyGeneratorFactory _factory;

    /** Name of the sequence. Defaults to "{0}_seq". */
    private String _sequence = "{0}_seq";
    
    /** Returning mode for the sequence. Used for Oracle. Defaults to "false". */
    private boolean _isReturning = false;
     
    /** Use a trigger that generates keys. Used for Oracle. Defaults to "false". */
    private boolean _isTrigger = false;
    
    /** Increment for the sequence. Used for interbase only. Defaults to "1". */
    private int _increment = 1;
    
    //--------------------------------------------------------------------------

    /**
     * Constructor for default SEQUENCE key generator.
     * 
     * @param factory The key generator factory that has created this key generator and
     *        will also be responsible to generate the DDL for the sequence.
     */
    protected SequenceKeyGenerator(final SequenceKeyGeneratorFactory factory)  {
        super(ALGORITHM_NAME, ALGORITHM_NAME);
        
        _factory = factory;
    }

    /**
     * Constructor for SEQUENCE key generator specified by given defintion.
     * 
     * @param factory The key generator factory that has created this key generator and
     *        will also be responsible to generate the DDL for the sequence.
     * @param definition Key generator definition.
     * @throws GeneratorException If increment parameter can't be parsed as integer.
     */
    protected SequenceKeyGenerator(final SequenceKeyGeneratorFactory factory,
                          final KeyGeneratorDef definition)
    throws GeneratorException {
        super(ALGORITHM_NAME, definition.getAlias());

        _factory = factory;
        
        Param []params = definition.getParam();
        for (int i = 0; i < params.length; i++) {
            String name = params[i].getName();
            String value = params[i].getValue();
            if (name == null) { continue; }
            if (PARAM_SEQUENCE.equalsIgnoreCase(name)) {
                _sequence = value;
            } else if (PARAM_RETURNING.equalsIgnoreCase(name)) {
                _isReturning = Boolean.valueOf(value).booleanValue();
            } else if (PARAM_TRIGGER.equalsIgnoreCase(name)) {
                _isTrigger = Boolean.valueOf(value).booleanValue();
            } else if (PARAM_INCREMENT.equalsIgnoreCase(name)) {
                try {
                    _increment = Integer.parseInt(value);
                } catch (NumberFormatException nfe) {
                    throw new GeneratorException("Can't parse integer" + name, nfe);
                }
            }            
        }                
    }

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

    /**
     * Get name of the sequence.
     * 
     * @return Name of the sequence.
     */
    public String getSequence() { return _sequence; }

    /**
     * Get returning mode for the sequence.
     * 
     * @return Returning mode for the sequence.
     */
    public boolean isReturning() { return _isReturning; }

    /**
     * Shell a trigger be used to generates keys?
     * 
     * @return <code>true</code> if keys are to be generated by a trigger,
     *         <code>false</code> otherwise. 
     */
    public boolean isTrigger() { return _isTrigger; }

    /**
     * Get increment for the sequence.
     * 
     * @return Increment for the sequence.
     */
    public int getIncrement() { return _increment; }

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

    /**
     * Delegate generation of create script to factory.
     * <br/>
     * {@inheritDoc}
     */
    public void toCreateDDL(final DDLWriter writer) {
        _factory.toCreateDDL(this, writer);
    }

    /**
     * Delegate generation of drop script to factory.
     * <br/>
     * {@inheritDoc}
     */
    public void toDropDDL(final DDLWriter writer) {
        _factory.toDropDDL(this, writer);
    }

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