/**
 * 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.camel.dataformat.barcode;

import java.util.Map;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

/**
 * This class tests all Camel independend test cases 
 * for {@link BarcodeDataFormat}.
 */
public class BarcodeDataFormatTest {
    
    /**
     * Test default constructor.
     */
    @Test
    public final void testDefaultConstructor() {
        BarcodeDataFormat barcodeDataFormat = new BarcodeDataFormat();
        this.checkParams(BarcodeParameters.IMAGE_TYPE
                , BarcodeParameters.WIDTH
                , BarcodeParameters.HEIGHT
                , BarcodeParameters.FORMAT
                , barcodeDataFormat.getParams());
    }
    
    /**
     * Test constructor with barcode format.
     */
    @Test
    public final void testConstructorWithBarcodeFormat() {
        BarcodeDataFormat barcodeDataFormat = 
                new BarcodeDataFormat(BarcodeFormat.AZTEC);
        this.checkParams(BarcodeParameters.IMAGE_TYPE
                , BarcodeParameters.WIDTH
                , BarcodeParameters.HEIGHT
                , BarcodeFormat.AZTEC
                , barcodeDataFormat.getParams());
    }
    
    /**
     * Test constructor with size.
     */
    @Test
    public final void testConstructorWithSize() {
        BarcodeDataFormat barcodeDataFormat = 
                new BarcodeDataFormat(200, 250);
        this.checkParams(BarcodeParameters.IMAGE_TYPE
                , 200, 250
                , BarcodeParameters.FORMAT
                , barcodeDataFormat.getParams());
    }
    
    /**
     * Test constructor with image type.
     */
    @Test
    public final void testConstructorWithImageType() {
        BarcodeDataFormat barcodeDataFormat = 
                new BarcodeDataFormat(BarcodeImageType.JPG);
        this.checkParams(BarcodeImageType.JPG
                , BarcodeParameters.WIDTH
                , BarcodeParameters.HEIGHT
                , BarcodeParameters.FORMAT
                , barcodeDataFormat.getParams());
    }
    
    /**
     * Test constructor with all.
     */
    @Test
    public final void testConstructorWithAll() {
        BarcodeDataFormat barcodeDataFormat = 
                new BarcodeDataFormat(200, 250, BarcodeImageType.JPG
                        , BarcodeFormat.AZTEC);
        this.checkParams(BarcodeImageType.JPG
                , 200, 250
                , BarcodeFormat.AZTEC
                , barcodeDataFormat.getParams());
    }

    /**
     * Test of optimizeHints method, of class BarcodeDataFormat.
     */
    @Test
    public final void testOptimizeHints() {
        BarcodeDataFormat instance = new BarcodeDataFormat();
        assertTrue(instance.getWriterHintMap()
                .containsKey(EncodeHintType.ERROR_CORRECTION));
        assertTrue(instance.getReaderHintMap()
                .containsKey(DecodeHintType.TRY_HARDER));
    }
    
    /**
     * Test optimized hints for data matrix.
     */
    @Test
    public final void testOptimizieHintsForDataMatrix() {
        BarcodeDataFormat instance = new BarcodeDataFormat(BarcodeFormat.DATA_MATRIX);
        assertTrue("data matrix shape hint incorrect.", 
                instance.getWriterHintMap()
                        .containsKey(EncodeHintType.DATA_MATRIX_SHAPE));
        assertTrue("try harder hint incorrect.",
                instance.getReaderHintMap()
                        .containsKey(DecodeHintType.TRY_HARDER));
    }

    /**
     * Test re-optimize hints.
     */
    @Test
    public final void testReOptimizeHints() {
        // DATA-MATRIX
        BarcodeDataFormat instance = new BarcodeDataFormat(BarcodeFormat.DATA_MATRIX);
        assertTrue(instance.getWriterHintMap()
                        .containsKey(EncodeHintType.DATA_MATRIX_SHAPE));
        assertTrue(instance.getReaderHintMap()
                        .containsKey(DecodeHintType.TRY_HARDER));

        // -> QR-CODE
        instance.setBarcodeFormat(BarcodeFormat.QR_CODE);
        assertFalse(instance.getWriterHintMap()
                        .containsKey(EncodeHintType.DATA_MATRIX_SHAPE));
        assertTrue(instance.getReaderHintMap()
                        .containsKey(DecodeHintType.TRY_HARDER));
    }

    /**
     * Test of addToHintMap method, of class BarcodeDataFormat.
     */
    @Test
    public final void testAddToHintMapEncodeHintTypeObject() {
        EncodeHintType hintType = EncodeHintType.MARGIN;
        Object value = 10;
        BarcodeDataFormat instance = new BarcodeDataFormat();
        instance.addToHintMap(hintType, value);
        assertTrue(instance.getWriterHintMap().containsKey(hintType));
        assertEquals(instance.getWriterHintMap().get(hintType), value);
    }

    /**
     * Test of addToHintMap method, of class BarcodeDataFormat.
     */
    @Test
    public final void testAddToHintMapDecodeHintTypeObject() {
        DecodeHintType hintType = DecodeHintType.CHARACTER_SET;
        Object value = "UTF-8";
        BarcodeDataFormat instance = new BarcodeDataFormat();
        instance.addToHintMap(hintType, value);
        assertTrue(instance.getReaderHintMap().containsKey(hintType));
        assertEquals(instance.getReaderHintMap().get(hintType), value);
    }

    /**
     * Test of removeFromHintMap method, of class BarcodeDataFormat.
     */
    @Test
    public final void testRemoveFromHintMapEncodeHintType() {
        EncodeHintType hintType = EncodeHintType.ERROR_CORRECTION;
        BarcodeDataFormat instance = new BarcodeDataFormat();
        instance.removeFromHintMap(hintType);
        assertFalse(instance.getWriterHintMap().containsKey(hintType));
    }

    /**
     * Test of removeFromHintMap method, of class BarcodeDataFormat.
     */
    @Test
    public final void testRemoveFromHintMapDecodeHintType() {
        DecodeHintType hintType = DecodeHintType.TRY_HARDER;
        BarcodeDataFormat instance = new BarcodeDataFormat();
        instance.removeFromHintMap(hintType);
        assertFalse(instance.getReaderHintMap().containsKey(hintType));
    }

    /**
     * Test of getParams method, of class BarcodeDataFormat.
     */
    @Test
    public final void testGetParams() {
        BarcodeDataFormat instance = new BarcodeDataFormat();
        BarcodeParameters result = instance.getParams();
        assertNotNull(result);
    }

    /**
     * Test of getWriterHintMap method, of class BarcodeDataFormat.
     */
    @Test
    public final void testGetWriterHintMap() {
        BarcodeDataFormat instance = new BarcodeDataFormat();
        Map<EncodeHintType, Object> result = instance.getWriterHintMap();
        assertNotNull(result);
    }

    /**
     * Test of getReaderHintMap method, of class BarcodeDataFormat.
     */
    @Test
    public final void testGetReaderHintMap() {
        BarcodeDataFormat instance = new BarcodeDataFormat();
        Map<DecodeHintType, Object> result = instance.getReaderHintMap();
        assertNotNull(result);
    }
    
    /**
     * Helper to check the saved parameters.
     * 
     * @param imageType
     * @param width
     * @param height
     * @param encoding
     * @param format
     * @param params 
     */
    private void checkParams(BarcodeImageType imageType, int width, int height
            , BarcodeFormat format, BarcodeParameters params) {
        assertEquals(params.getType(), imageType);
        assertTrue(params.getWidth() == width);
        assertTrue(params.getHeight() == height);
        assertEquals(params.getFormat(), format);
    }
}
