/*
 * Copyright (c) 2022, ctecinf.com.br
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package br.com.ctecinf.text;

import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

/**
 *
 * @author Cássio Conceição
 * @since 01/11/2019
 * @version 2203
 * @see http://ctecinf.com.br/
 */
public class MaskFormatter extends JFormattedTextField.AbstractFormatter {

    public static final String CPF = "###.###.###-##";
    public static final String CEP = "#####-###";
    public static final String CNPJ = "##.###.###/####-##";
    public static final String PHONE = "## #####-####";

    private static final String MASK_PHONE_8 = "## ####-####";
    private static final String MASK_PHONE_9 = "## #####-####";

    private String mask = "";
    private boolean isPhone = false;

    public MaskFormatter(String mask) {

        this.mask = mask;

        if (mask.equalsIgnoreCase(MASK_PHONE_8) || mask.equalsIgnoreCase(MASK_PHONE_9)) {
            isPhone = true;
        }
    }

    private int length(String m) {

        int length = 0;

        for (char c : m.toCharArray()) {
            if (c == '#') {
                length++;
            }
        }

        return length;
    }

    private final DocumentFilter df = new DocumentFilter() {
        @Override
        public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {

            if (!Character.isDigit(text.charAt(length))) {
                return;
            }

            if (isPhone) {

                if (offset == 1) {
                    text += " ";
                }

                if (offset == 6) {
                    text += "-";
                }

                if (offset == MASK_PHONE_9.length() - 1) {
                    super.remove(fb, 7, 1);
                    super.insertString(fb, 8, "-", attrs);
                    super.replace(fb, offset, length, text, attrs);
                    getFormattedTextField().transferFocus();
                    return;
                }

                super.replace(fb, offset, length, text, attrs);

            } else {

                if (offset == mask.length() - 1) {
                    getFormattedTextField().transferFocus();
                }

                if (offset >= mask.length()) {
                    return;
                }

                if (text.length() < length || !Character.isDigit(text.charAt(length))) {
                    return;
                }

                if (mask.charAt(offset) != '#') {
                    text = String.valueOf(mask.charAt(offset)) + text;
                }

                super.replace(fb, offset, length, text, attrs);
            }
        }
    };

    @Override
    public Object stringToValue(String text) throws ParseException {

        if (isPhone) {

            if (text == null || text.isEmpty() || text.length() < MASK_PHONE_9.length() - 1) {
                getFormattedTextField().setValue(null);
                return null;
            }

            return text.replace(".", "").replace("-", "").replace("/", "").replace("(", "").replace(")", "").replace(" ", "").trim();

        } else {

            if (text.isEmpty() || text.length() < mask.length()) {
                getFormattedTextField().setValue(null);
                return null;
            }

            String str = "";

            for (int i = 0; i < mask.toCharArray().length; i++) {
                if (mask.charAt(i) == '#') {
                    str += text.charAt(i);
                }
            }

            return str.isEmpty() ? null : str;
        }
    }

    @Override
    public String valueToString(Object value) throws ParseException {

        if (value == null || !value.getClass().isAssignableFrom(String.class)) {
            return "";
        }

        String str = value.toString().replace(".", "").replace("-", "").replace("/", "").replace("(", "").replace(")", "").replace(" ", "").trim();

        if (isPhone) {

            String maskPhone = MASK_PHONE_8;

            if (str.length() == length(MASK_PHONE_9)) {
                maskPhone = MASK_PHONE_9;
            }

            if (str.length() < length(MASK_PHONE_8)) {
                return "";
            } else {
                return MaskFormatter.format(str, maskPhone);
            }

        } else if (str.length() == length(mask)) {
            return MaskFormatter.format(str, mask);
        }

        return "";
    }

    public static String format(String value, String mask) {

        String str = "";
        int index = 0;

        for (char c : mask.toCharArray()) {

            if (c == '#') {
                str += value.charAt(index);
                index++;
            } else {
                str += c;
            }
        }

        return str;
    }

    @Override
    protected DocumentFilter getDocumentFilter() {
        return df;
    }
}
