/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.pdfbox.pdmodel.interactive.form;

import org.apache.pdfbox.cos.COSDictionary;

import java.io.IOException;

/**
 * This is the Factory for creating and returning the correct
 * field elements.
 *
 * @author sug
 * @version $Revision: 1.8 $
 */
public class PDFieldFactory
{
    private static final int RADIO_BITMASK = 32768;
    private static final int PUSHBUTTON_BITMASK = 65536;

    private static final String FIELD_TYPE_BTN = "Btn";
    private static final String FIELD_TYPE_TX = "Tx";
    private static final String FIELD_TYPE_CH = "Ch";
    private static final String FIELD_TYPE_SIG = "Sig";

    /**
     * Utility class so no constructor.
     */
    private PDFieldFactory()
    {
        //do nothing.
    }

    /**
     * This method creates a COSField subclass from the given field.
     * The field is a PDF Dictionary object that must represent a
     * field element. - othewise null is returned
     *
     * @param acroForm The form that the field will be part of.
     * @param field The dictionary representing a field element
     *
     * @return a subclass to COSField according to the kind of field passed to createField
     * @throws IOException If there is an error determining the field type.
     */
    public static PDField createField( PDAcroForm acroForm, COSDictionary field) throws IOException
    {
        PDField pdField = new PDUnknownField( acroForm, field );
        if( isButton(pdField) )
        {
            int flags = pdField.getFieldFlags();
            if(isRadio(flags) )
            {
                pdField = new PDRadioCollection( acroForm, field );
            }
            else if( isPushButton( flags ) )
            {
                pdField = new PDPushButton( acroForm, field );
            }
            else
            {
                pdField = new PDCheckbox( acroForm, field );
            }

        }
        else if (isChoiceField(pdField))
        {
            pdField = new PDChoiceField( acroForm, field );
        }
        else if (isTextbox(pdField))
        {
            pdField = new PDTextbox( acroForm, field );
        }
        else if( isSignature( pdField ) )
        {
            pdField = new PDSignatureField( acroForm, field );
        }
        else
        {
            //do nothing and return an unknown field type.
        }
        return pdField;
    }

    /**
     * This method determines if the given
     * field is a radiobutton collection.
     *
     * @param flags The field flags.
     *
     * @return the result of the determination
     */
    private static boolean isRadio( int flags )
    {
        return (flags & RADIO_BITMASK) > 0;
    }

    /**
     * This method determines if the given
     * field is a pushbutton.
     *
     * @param flags The field flags.
     *
     * @return the result of the determination
     */
    private static boolean isPushButton( int flags )
    {
        return (flags & PUSHBUTTON_BITMASK) > 0;
    }

    /**
     * This method determines if the given field is a choicefield
     * Choicefields are either listboxes or comboboxes.
     *
     * @param field the field to determine
     * @return the result of the determination
     */
    private static boolean isChoiceField(PDField field) throws IOException
    {
        return FIELD_TYPE_CH.equals(field.findFieldType());
    }

    /**
     * This method determines if the given field is a button.
     *
     * @param field the field to determine
     * @return the result of the determination
     *
     * @throws IOException If there is an error determining the field type.
     */
    private static boolean isButton(PDField field) throws IOException
    {
        String ft = field.findFieldType();
        return FIELD_TYPE_BTN.equals( ft );
    }

   /**
     * This method determines if the given field is a signature.
     *
     * @param field the field to determine
     * @return the result of the determination
     */
    private static boolean isSignature(PDField field) throws IOException
    {
        return FIELD_TYPE_SIG.equals(field.findFieldType());
    }

    /**
     * This method determines if the given field is a Textbox.
     *
     * @param field the field to determine
     * @return the result of the determination
     */
    private static boolean isTextbox(PDField field) throws IOException
    {
        return FIELD_TYPE_TX.equals(field.findFieldType());
    }
}
