package org.okou.lippen.network.tool.ui.field;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputMethodListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;

/**
 * IPV4地址输入框
 */
public class IPV4Field extends JTextField implements Serializable {
    private static final Border EMPTY_BORDER = BorderFactory
            .createEmptyBorder();
    private static final long serialVersionUID = -2754807884601930339L;

    private Dot[] dots;

    private JIPV4Field[] ipFields;
    private KeyAdapter KeyListener = new IPKeyAdapter();

    public IPV4Field() {
        this(null);
    }

    public IPV4Field(String ipAddress) {
        setLayout(new GridLayout(1, 4, 0, 0));
        setFocusable(false);
        createIPFields();
        setIpAddress(ipAddress);
    }

    @Override
    public void addFocusListener(FocusListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.addFocusListener(listener);
            }
        }
    }

    @Override
    public void removeFocusListener(FocusListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.removeFocusListener(listener);
            }
        }
    }

    @Override
    public void addInputMethodListener(InputMethodListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.addInputMethodListener(listener);
            }
        }
    }

    @Override
    public void removeInputMethodListener(InputMethodListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.removeInputMethodListener(listener);
            }
        }
    }

    @Override
    public void addCaretListener(CaretListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.addCaretListener(listener);
            }
        }
    }

    @Override
    public void removeCaretListener(CaretListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.removeCaretListener(listener);
            }
        }
    }

    public void addDocumentListener(DocumentListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.getDocument().addDocumentListener(listener);
            }
        }
    }

    public void removeDocumentListener(DocumentListener listener) {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.getDocument().removeDocumentListener(listener);
            }
        }
    }

    /**
     * 是否输入完整。<br>
     * 如果有一个输入域为空,则认为没有输入完整
     */
    public boolean isInputAll() {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                if (field.getText() == null || field.getText().isEmpty()) {
                    return false;
                }
            }
        }
        return true;
    }

    private void createIPFields() {
        updatePrefersize();
        this.ipFields = new JIPV4Field[4];
        this.dots = new Dot[3];
        JPanel[] fieldPanes = new JPanel[4];

        for (int i = 0; i < 4; i++) {
            this.ipFields[i] = new JIPV4Field();
            fieldPanes[i] = new JPanel();

            this.ipFields[i].addKeyListener(this.KeyListener);
            fieldPanes[i].setOpaque(false);
            fieldPanes[i].setLayout(new BorderLayout());
            fieldPanes[i].add(this.ipFields[i], "Center");

            if (i != 3) {
                fieldPanes[i].add(dots[i] = new Dot(), "East");
            }

            add(fieldPanes[i]);
        }

        for (int i = 0; i < 4; i++) {
            if (i == 0) {
                this.ipFields[i]
                        .addPropertyChangeListener(new KeyPressListener(null,
                                this.ipFields[(i + 1)]));
            } else if (i == 3) {
                this.ipFields[i]
                        .addPropertyChangeListener(new KeyPressListener(
                                this.ipFields[(i - 1)], null));
            } else {
                this.ipFields[i]
                        .addPropertyChangeListener(new KeyPressListener(
                                this.ipFields[(i - 1)], this.ipFields[(i + 1)]));
            }
        }
    }

    protected void updatePrefersize() {
        Dimension size = new Dimension(80, getFont().getSize() * 2);
        size.width = getFont().getSize() * 11;
        setPreferredSize(size);
    }

    public JTextField[] getFieldComponents() {
        return this.ipFields;
    }

    @Override
    public void requestFocus() {
        if (ipFields != null) {
            ipFields[0].requestFocus();
        }
    }

    public String getIpAddress() {
        StringBuilder ip = new StringBuilder();
        int emptyCount = 0;

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                String str = field.getText();

                if (str.isEmpty()) {
                    emptyCount++;
                }

                ip.append('.');
                ip.append(str);
            }

            ip.deleteCharAt(0);
        }

        return emptyCount == 4 ? "" : ip.toString();
    }

    @Override
    public String getText() {
        return getIpAddress();
    }

    @Override
    public void setCaretColor(Color color) {
        super.setCaretColor(color);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setCaretColor(color);
            }
        }
    }

    @Override
    public void setDisabledTextColor(Color color) {
        super.setDisabledTextColor(color);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setDisabledTextColor(color);

                if (field.isEnabled())
                    continue;
                field.repaint();
            }

        }

        if ((this.dots != null) && (!isEnabled())) {
            for (Dot dot : this.dots) {
                dot.setForeground(color);
            }
        }
    }

    @Override
    public void setEditable(boolean isEditable) {
        super.setEditable(isEditable);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setEditable(isEditable);
            }
        }
    }

    @Override
    public void setEnabled(boolean isEnable) {
        super.setEnabled(isEnable);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setEnabled(isEnable);
            }
        }

        if (this.dots != null) {
            for (Dot dot : this.dots) {
                dot.setForeground(isEnable ? getForeground()
                        : getDisabledTextColor());
            }
        }
    }

    @Override
    public void setFont(Font font) {
        super.setFont(font);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setFont(font);
            }
        }
        /*
         * if (this.dots != null) { for (Dot dot : this.dots) {
         * dot.setFont(font); } }
         */
    }

    @Override
    public void setForeground(Color color) {
        super.setForeground(color);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setForeground(color);
            }
        }

        if ((this.dots != null) && (isEnabled())) {
            for (Dot dot : this.dots) {
                dot.setForeground(color);
            }
        }
    }

    public void setIpAddress(String ipAddress) {
        int index;

        if ((ipAddress != null) && (!ipAddress.isEmpty())) {
            if (!Pattern
                    .matches(
                            "((2[0-4]\\d|25[0-5]|[01]?\\d?\\d)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d?\\d)",
                            ipAddress)) {
                throw new IllegalArgumentException("Invalid IP Address:"
                        + ipAddress);
            }

            String[] ipBit = ipAddress.split("\\.");
            index = 0;

            for (JIPV4Field field : this.ipFields) {
                field.setText(Integer.parseInt(ipBit[(index++)]) + "");
            }
        } else {
            for (JIPV4Field field : this.ipFields) {
                field.setText("");
            }
        }
    }

    /**
     * 已整数形式设置IP地址
     *
     * @param ip
     */
    public void setIpValue(int ip) {
        setIpAddress(toIPString(ip));
    }

    /**
     * 获取IP地址的整数
     *
     * @return
     */
    public int getIPValue() {
        int ip = 0;
        ip = (ip << 8) | ipFields[0].getIntValue();
        ip = (ip << 8) | ipFields[1].getIntValue();
        ip = (ip << 8) | ipFields[2].getIntValue();
        ip = (ip << 8) | ipFields[3].getIntValue();
        return ip;
    }

    /**
     * 清空IP地址
     */
    public void clearIPAddress() {
        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setText("");
            }
        }
    }

    public static String toIPString(int ip) {
        return ((ip >> 24) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "."
                + ((ip >> 8) & 0xFF) + "." + ((ip >> 0) & 0xFF);
    }

    @Override
    public void setSelectedTextColor(Color color) {
        super.setSelectedTextColor(color);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setSelectedTextColor(color);
            }
        }
    }

    @Override
    public void setSelectionColor(Color color) {
        super.setSelectionColor(color);

        if (this.ipFields != null) {
            for (JIPV4Field field : this.ipFields) {
                field.setSelectionColor(color);
            }
        }
    }

    @Override
    public void setText(String text) {
        setIpAddress(text);
    }

    @Override
    public void updateUI() {
        Component[] children = getComponents();

        for (Component child : children) {
            remove(child);
        }

        super.updateUI();

        for (Component child : children) {
            add(child);
        }

        if (getCaret() != null) {
            getCaret().deinstall(this);
        }
    }

    private class Dot extends JLabel {
        private static final long serialVersionUID = -2704811830155290868L;

        public Dot() {
            super();
            setText(".");
            setOpaque(false);
            setIconTextGap(0);
            setFont(new Font(Font.DIALOG, Font.BOLD, 12));
            setBorder(IPV4Field.EMPTY_BORDER);
            setForeground(IPV4Field.this.getForeground());
            setEnabled(IPV4Field.this.isEnabled());
            setHorizontalAlignment(JLabel.CENTER);
        }

        @Override
        public void setEnabled(boolean enabled) {
            super.setEnabled(enabled);
            setForeground(enabled ? IPV4Field.this.getForeground()
                    : IPV4Field.this.getDisabledTextColor());
        }

        @Override
        public void updateUI() {
            super.updateUI();
            setFont(IPV4Field.this.getFont());
        }
    }

    private class JIPV4Field extends JTextField implements ActionListener,
            FocusListener, Serializable {
        private static final long serialVersionUID = 1411564647463716520L;
        private boolean selectAll;

        public JIPV4Field() {
            this.selectAll = true;
            setHorizontalAlignment(0);
            setBorder(IPV4Field.EMPTY_BORDER);
            setOpaque(false);
            setMargin(new Insets(0, 0, 0, 0));
            setDocument(new IPBlockDocument(this));
            setFont(IPV4Field.this.getFont());
            setSelectionColor(IPV4Field.this.getSelectionColor());
            setSelectedTextColor(IPV4Field.this.getSelectedTextColor());
            setEditable(IPV4Field.this.isEditable());
            setDisabledTextColor(IPV4Field.this.getDisabledTextColor());
            setCaretColor(IPV4Field.this.getCaretColor());
            setForeground(IPV4Field.this.getForeground());
            setEnabled(IPV4Field.this.isEnabled());
            addActionListener(this);
            addFocusListener(this);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            transferFocus();
        }

        @Override
        public void focusGained(FocusEvent e) {
            if (this.selectAll) {
                selectAll();
            } else {
                this.selectAll = true;
            }
        }

        @Override
        public void focusLost(FocusEvent e) {
        }

        public void unSelectAllWhenFocusGained() {
            if (!isFocusOwner()) {
                this.selectAll = false;
            }
        }

        /**
         * 获取值
         *
         * @return
         */
        public int getIntValue() {
            String value = this.getText();
            if (value == null || value.isEmpty()) {
                return 0;
            }
            return Integer.parseInt(value);
        }

        private class IPBlockDocument extends PlainDocument {
            private static final long serialVersionUID = -2645957214215338331L;
            private final Pattern INT_PATTERN = Pattern
                    .compile("0|([1-9]\\d*)?");

            private int ipBlockInt;
            private int length;
            private Matcher matcher;
            private int newLength;
            private int oldLength;
            private StringBuilder text = new StringBuilder();
            private JTextField textField;

            private IPBlockDocument(JTextField textField) {
                this.textField = textField;
            }

            @Override
            public void insertString(int offset, String input, AttributeSet a)
                    throws BadLocationException {
                this.matcher = INT_PATTERN.matcher(input);
                if (!this.matcher.matches()) {
                    return;
                }
                this.oldLength = getLength();
                this.newLength = input.length();
                this.length = (this.oldLength + this.newLength);
                this.text.delete(0, this.text.length());// clear
                this.text.append(getText(0, this.oldLength));// add old
                this.text.insert(offset, input);// replace or add
                if ((this.length > 3)) {

                    return;
                }

                this.ipBlockInt = (this.text.length() == 0 ? 0 : Integer
                        .parseInt(this.text.toString()));

                if (this.ipBlockInt > 255) {
                    return;
                }

                super.insertString(offset, input, a);
                if (this.length == 3) {
                    textField.firePropertyChange("Right", 0, 1);
                }
                if (this.text.length() == 2
                        && Integer.parseInt(this.text.toString()) > 25) {
                    textField.firePropertyChange("Right", 0, 1);
                }
            }
        }

    }

    private class KeyPressListener implements PropertyChangeListener {
        private IPV4Field.JIPV4Field leftField;
        private IPV4Field.JIPV4Field rightField;

        public KeyPressListener(IPV4Field.JIPV4Field leftField,
                                IPV4Field.JIPV4Field rightField) {
            this.leftField = leftField;
            this.rightField = rightField;
        }

        public void propertyChange(PropertyChangeEvent evt) {
            String name = evt.getPropertyName();

            if ((name == "Left") && (this.leftField != null)) {
                this.leftField.requestFocus();
            } else if ((name == "Right") && (this.rightField != null)) {
                this.rightField.requestFocus();
            } else if ((name == "BackSpace") && (this.leftField != null)) {
                this.leftField.unSelectAllWhenFocusGained();
                this.leftField.requestFocus();
                this.leftField.setCaretPosition(this.leftField.getText()
                        .length());
            } else if ((name == "Delete") && (this.rightField != null)) {
                this.rightField.unSelectAllWhenFocusGained();
                this.rightField.requestFocus();
                this.rightField.setCaretPosition(0);
            }
        }
    }

    class IPKeyAdapter extends KeyAdapter {
        public void keyPressed(KeyEvent e) {
            JTextComponent field = (JTextComponent) e.getComponent();
            int keyCode = e.getKeyCode();
            char keyChar = e.getKeyChar();
            String text = field.getText();
            String selText = field.getSelectedText();
            int caretPos = field.getCaretPosition();
            int textLength = text.length();
            if ((keyCode == KeyEvent.VK_LEFT) && (caretPos == 0)
                    && (selText == null)) {
                field.firePropertyChange("Left", 0, 1);
            } else if (((keyCode == KeyEvent.VK_RIGHT)
                    && (caretPos == textLength) && (selText == null))
                    || ((keyChar == '.') && (!text.isEmpty()) && (selText == null))) {
                field.firePropertyChange("Right", 0, 1);
            } else if ((keyCode == KeyEvent.VK_BACK_SPACE) && (caretPos == 0)
                    && (selText == null)) {
                field.firePropertyChange("BackSpace", 0, 1);
            } else if ((keyCode == KeyEvent.VK_DELETE)
                    && (caretPos == textLength) && (selText == null)) {
                field.firePropertyChange("Delete", 0, 1);
            } else if (keyCode == KeyEvent.VK_HOME) {
                IPV4Field.this.ipFields[0].unSelectAllWhenFocusGained();
                IPV4Field.this.ipFields[0].requestFocus();
                IPV4Field.this.ipFields[0].setCaretPosition(0);
            } else if (keyCode == KeyEvent.VK_END) {
                int last = IPV4Field.this.ipFields.length - 1;
                textLength = IPV4Field.this.ipFields[last].getText()
                        .length();
                IPV4Field.this.ipFields[last]
                        .unSelectAllWhenFocusGained();
                IPV4Field.this.ipFields[last].requestFocus();
                IPV4Field.this.ipFields[last]
                        .setCaretPosition(textLength);
            } else if ((keyCode == KeyEvent.VK_0 || keyCode == KeyEvent.VK_NUMPAD0) && (caretPos == 0 || (text != null && text.equals(selText)))) {
                field.firePropertyChange("Right", 0, 1);
            } else if (("0123456789".indexOf(keyChar) >= 0)) {
                if (selText == null) {
                    int ipInt = (text.length() == 0 ? 0 : Integer
                            .parseInt(text));

                    if (ipInt > 25) {
                        field.firePropertyChange("Right", 0, 1);
                    }
                } else {
                    if (field.getSelectionStart() == 2
                            && field.getSelectionEnd() == 3) {
                        field.firePropertyChange("Right", 0, 1);
                    }
                }
            }
        }
    }

    ;

    public static void main(String[] args) {
        IPV4Field ipFiled = new IPV4Field();
        ipFiled.setIpAddress("192.168.131.1");
        //ipFiled.setIpValue(12345);
        JPanel pl = new JPanel();
        pl.add(ipFiled);
        JFrame frame = new JFrame();
        frame.add(pl);
        frame.setSize(new Dimension(200, 100));
        frame.setVisible(true);
    }

}