/*
 * Copyright (C) 2023 ctecinf.com.br
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package br.com.ctecinf.qrcode;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;

/**
 *
 * @author Cássio Conceição
 * @since 13/06/2023
 * @version 2306
 * @see http://hobbyslotcar.com.br
 */
public class QRCode {

    public static final int NUM_MASK_PATTERNS = 8;

    private Mode mode;
    private ErrorCorrectionLevel ecLevel;
    private Version version;
    private int maskPattern;
    private ByteMatrix matrix;

    public QRCode() {
        maskPattern = -1;
    }

    /**
     * @return the mode. Not relevant if
     * {@link com.google.zxing.EncodeHintType#QR_COMPACT} is selected.
     */
    public Mode getMode() {
        return mode;
    }

    public ErrorCorrectionLevel getECLevel() {
        return ecLevel;
    }

    public Version getVersion() {
        return version;
    }

    public int getMaskPattern() {
        return maskPattern;
    }

    public ByteMatrix getMatrix() {
        return matrix;
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder(200);
        result.append("<<\n");
        result.append(" mode: ");
        result.append(mode);
        result.append("\n ecLevel: ");
        result.append(ecLevel);
        result.append("\n version: ");
        result.append(version);
        result.append("\n maskPattern: ");
        result.append(maskPattern);
        if (matrix == null) {
            result.append("\n matrix: null\n");
        } else {
            result.append("\n matrix:\n");
            result.append(matrix);
        }
        result.append(">>\n");
        return result.toString();
    }

    public void setMode(Mode value) {
        mode = value;
    }

    public void setECLevel(ErrorCorrectionLevel value) {
        ecLevel = value;
    }

    public void setVersion(Version version) {
        this.version = version;
    }

    public void setMaskPattern(int value) {
        maskPattern = value;
    }

    public void setMatrix(ByteMatrix value) {
        matrix = value;
    }

    // Check if "mask_pattern" is valid.
    public static boolean isValidMaskPattern(int maskPattern) {
        return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
    }

    /**
     * Gera QRCode tamanho DEFAULT 100 x 100
     *
     * @param content Conteúdo
     * @return File
     * @throws java.io.IOException
     * @throws br.com.ctecinf.qrcode.WriterException
     */
    public static File create(String content) throws IOException, WriterException {
        return QRCode.create(content, 100);
    }

    /**
     * Gera QRCode
     *
     * @param content Conteúdo
     * @param width Tamanho
     * @return File
     * @throws java.io.IOException
     * @throws br.com.ctecinf.qrcode.WriterException
     */
    public static File create(String content, int width) throws IOException, WriterException {

        File file = new File("qrcode", content.replace(File.separator, "_").replace(" ", "") + ".png");

        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }

        HashMap<EncodeHintType, ErrorCorrectionLevel> hintMap = new HashMap<>();
        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);

        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, width, hintMap);
        int crunchifyWidth = byteMatrix.getWidth();

        BufferedImage image = new BufferedImage(crunchifyWidth, crunchifyWidth, BufferedImage.TYPE_INT_RGB);
        image.createGraphics();

        Graphics2D graphics = (Graphics2D) image.getGraphics();
        graphics.setColor(Color.WHITE);
        graphics.fillRect(0, 0, crunchifyWidth, crunchifyWidth);
        graphics.setColor(Color.BLACK);

        for (int i = 0; i < crunchifyWidth; i++) {
            for (int j = 0; j < crunchifyWidth; j++) {
                if (byteMatrix.get(i, j)) {
                    graphics.fillRect(i, j, 1, 1);
                }
            }
        }

        ImageIO.write(image, "png", file);

        return file;
    }
}
