package jp.sourceforge.projects.ee2e.core.editors;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;

/**
 * To change this generated comment edit the template variable "typecomment":
 * Window&gt;Preferences&gt;Java&gt;Templates.
 * To enable and disable the creation of type comments go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation.
 *
 * @author Toshikazu Ando [ ando@park.ruru.ne.jp ]
 */
public class EE2EIndentSnmp extends EE2EIndentBehavior {
    /** constractor */
    public EE2EIndentSnmp(int snmpIndentLevel) {
        //
        this.snmpIndentLevel = snmpIndentLevel;
    }

    /**
     * @see jp.sourceforge.projects.ee2e.core.editors.EE2EMenuBehavior#tabDestroyer(AbstractTextEditor, IDocument, ITextSelection)
     */
    protected void doIndent(int argumentOffset, IDocument document)
        throws BadLocationException {
        int indent = this.doSnmpCalculateIndent(argumentOffset, document);
        EE2ELispBase.get().indentTo(argumentOffset, indent, document);
    }

    /**
     * (defun snmp-calculate-indent ()
     *   (let ((empty (concat "\\([ \t]*\\)\\(" comment-start-skip "\\|$\\)"))
     *         (case-fold-search nil)) ; keywords must be in uppercase
     *     (save-excursion
     *       (while (and (>= (forward-line -1) 0)
     *                   (looking-at empty)))
     *       (skip-chars-forward " \t")
     *       (+ (current-column)
     *          ;; Are we looking at a macro open string?  If so, add more.
     *          (cond ((looking-at snmp-macro-open)
     *                 snmp-indent-level)
     *                ;; macro close string?  If so, remove some.
     *                ((looking-at snmp-macro-close)
     *                 (- snmp-indent-level))
     *                ;; Neither; just stay here.
     *                (t 0))))))
     */
    protected int doSnmpCalculateIndent(int argumentOffset, IDocument document)
        throws BadLocationException {
        int ans = 0;
        int nowOffset = argumentOffset;

        nowOffset = EE2ELispBase.get().beginningOfLine(nowOffset, document);
        if (nowOffset <= 0) {
            return 0;
        }
        nowOffset =
            EE2ELispBase.get().skipCharsForward(nowOffset, " \t\n\r", document);
        if (this.lookinAtFunctionObject(nowOffset + 1, document)) {
            int ansObject = this.checkObject(nowOffset, document);
            if (0 <= ansObject) {
                return ansObject;
            }
        }
        nowOffset =
            EE2ELispBase.get().skipCharsBackward(
                nowOffset - 1,
                " \t\n\r",
                document);
        nowOffset = EE2ELispBase.get().beginningOfLine(nowOffset, document);
        nowOffset = this.commentSkip(nowOffset, document);
        if (nowOffset < 0) {
            return 0;
        }
        ans = EE2ELispBase.get().indentLen(nowOffset, document);
        for (; nowOffset < document.getLength(); nowOffset++) {
            char ch = document.getChar(nowOffset);
            if ((ch != ' ') && (ch != '\t') && (ch != '\n') && (ch != '\r')) {
                break;
            }
        }

        if (this.lookingAtSnmpMacroOpen(nowOffset, document)) {
            // Are we looking at a macro open string?  If so, add more.
            ans += snmpIndentLevel;
        } else if (this.lookingAtSnmpMacroClose(nowOffset, document)) {
            // macro close string?  If so, remove some.
            ans -= snmpIndentLevel;
        }
        // Neither; just stay here.
        return ans;
    }
    protected int checkObject(int argumentOffset, IDocument document)
        throws BadLocationException {
        int offset = argumentOffset;
        offset =
            EE2ELispBase.get().skipCharsBackward(offset, " \t\r\n", document);
        if (offset <= 0) {
            return -1;
        }
        while (true) {
            offset = EE2ELispBase.get().beginningOfLine(offset - 1, document);
            if (offset <= 0) {
                break;
            }
            int nextOffset =
                EE2ELispBase.get().skipCharsForward(
                    offset,
                    " \t\r\n",
                    document);
            if (this.lookinAtFunctionObject(nextOffset + 1, document)) {
                int len =
                    EE2ELispBase.get().indentLen(nextOffset + 1, document);
                return len;
            }
        }
        return -1;
    }

    protected int commentSkip(int argumentOffset, IDocument document)
        throws BadLocationException {
        int offset = argumentOffset;
        while (true) {
            offset = EE2ELispBase.get().beginningOfLine(offset, document);
            if (offset <= 0) {
                return 0;
            }
            int nextOffset =
                EE2ELispBase.get().skipCharsForward(
                    offset,
                    " \t\r\n",
                    document);
            if (document.getLength() <= nextOffset + 2) {
                break;
            }
            char ch1 = document.getChar(nextOffset + 1);
            char ch2 = document.getChar(nextOffset + 2);
            if ((ch1 != '-') || (ch2 != '-')) {
                break;
            }
            offset--;
        }
        return offset;
    }

    /**
     * (defvar snmp-macro-open
     *   "[a-zA-Z][-a-zA-Z0-9]*[ \t]*\\(OBJECT\\|TRAP\\)-\\(TYPE\\|GROUP\\)\
     * \\|DESCRIPTION\\|IMPORTS\\|MODULE\\(-IDENTITY\\|-COMPLIANCE\\)\
     * \\|.*::=[ \t]*\\(BEGIN\\|TEXTUAL-CONVENTION\\)[ \t]*$")"
     */
    protected boolean lookingAtSnmpMacroOpen(
        int argumentOffset,
        IDocument document)
        throws BadLocationException {
        int offset = argumentOffset;
        if (this.lookinAtFunctionObject(argumentOffset, document)) {
            return true;
        }
        if (EE2ELispBase.get().lookingAt(argumentOffset, "DESCRIPTION", document)
            || EE2ELispBase.get().lookingAt(argumentOffset, "IMPORTS", document)
            || EE2ELispBase.get().lookingAt(argumentOffset, "MODULE-IDENTITY", document)
            || EE2ELispBase.get().lookingAt(argumentOffset, "MODULE-COMPLIANCE", document)) {
            return true;
        }
        int endOfLine = EE2ELispBase.get().endOfLine(offset, document);
        boolean flag = false;
        for (offset = endOfLine - 3; argumentOffset <= offset; offset--) {
            char ch1 = document.getChar(offset);
            char ch2 = document.getChar(offset + 1);
            char ch3 = document.getChar(offset + 2);
            if ((ch1 == ':') && (ch2 == ':') && (ch3 == '=')) {
                flag = true;
                break;
            }
        }
        if (!flag) {
            return false;
        }
        offset += 3;
        if (document.getLength() <= offset) {
            return false;
        }
        for (; offset < document.getLength(); offset++) {
            char ch = document.getChar(offset);
            if ((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) {
                break;
            }
        }
        if (document.getLength() <= offset) {
            return false;
        }
        String target = "BEGIN";
        if (EE2ELispBase.get().lookingAt(offset, target, document)) {
            if (this.isSpaceCheck(offset + target.length(), document)) {
                return true;
            }
            return false;
        }
        target = "TEXTUAL-CONVENTION";
        if (EE2ELispBase.get().lookingAt(offset, target, document)) {
            if (this.isSpaceCheck(offset + target.length(), document)) {
                return true;
            }
            return false;
        }
        return false;
    }

    /** [a-zA-Z][-a-zA-Z0-9]*[ \t]+\\(OBJECT\\|TRAP\\)-\\(TYPE\\|GROUP\\) */
    protected boolean lookinAtFunctionObject(
        int argumentOffset,
        IDocument document)
        throws BadLocationException {
        int offset = argumentOffset;
        if (document.getLength() <= argumentOffset) {
            return false;
        }
        char ch = document.getChar(offset);
        if ((ch < 'a') || ('z' < ch)) {
            return false;
        }
        offset++;
        if (document.getLength() <= offset) {
            return false;
        }
        for (; offset < document.getLength(); offset++) {
            ch = document.getChar(offset);
            if (((ch < 'a') || ('z' < ch))
                && ((ch < 'A') || ('Z' < ch))
                && ((ch < '0') || ('9' < ch))) {
                break;
            }
        }
        if (document.getLength() <= offset) {
            return false;
        }
        ch = document.getChar(offset);
        if ((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) {
            return false;
        }
        offset++;
        if (document.getLength() <= offset) {
            return false;
        }
        for (; offset < document.getLength(); offset++) {
            ch = document.getChar(offset);
            if ((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) {
                break;
            }
        }
        if (document.getLength() <= offset) {
            return false;
        }
        if (EE2ELispBase.get().lookingAt(offset, "OBJECT-TYPE", document)
            || EE2ELispBase.get().lookingAt(offset, "OBJECT-GROUP", document)
            || EE2ELispBase.get().lookingAt(offset, "TRAP-TYPE", document)
            || EE2ELispBase.get().lookingAt(offset, "TRAP-GROUP", document)) {
            return true;
        }
        return false;
    }

    /** (defvar snmp-macro-close
     * "::=[ \t]*{\\|\\(END\\|.*[;\"]\\)[ \t]*$")
     */
    protected boolean lookingAtSnmpMacroClose(
        int argumentOffset,
        IDocument document)
        throws BadLocationException {
        int offset = argumentOffset;
        String target = "END";
        if (EE2ELispBase.get().lookingAt(offset, target, document)) {
            if (this.isSpaceCheck(offset + target.length(), document)) {
                return true;
            }
            return false;
        }
        char ch;
        int endOfLine = EE2ELispBase.get().endOfLine(offset, document);
        for (int skipOffset = endOfLine; offset <= skipOffset; skipOffset--) {
            ch = document.getChar(skipOffset);
            if (ch == ';') {
                if (this.isSpaceCheck(skipOffset + 1, document)) {
                    return true;
                }
                return false;
            }
        }
        target = "::=";
        if (!EE2ELispBase.get().lookingAt(offset, target, document)) {
            return false;
        }
        offset += target.length();
        for (; offset < document.getLength(); offset++) {
            ch = document.getChar(offset);
            if ((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) {
                break;
            }
        }
        ch = document.getChar(offset);
        if (ch == '{') {
            return true;
        }
        return false;
    }
    protected boolean isSpaceCheck(int argumentOffset, IDocument document)
        throws BadLocationException {
        int endOfLine = EE2ELispBase.get().endOfLine(argumentOffset, document);
        for (int offset = argumentOffset; offset <= endOfLine; offset++) {
            char ch = document.getChar(offset);
            if ((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) {
                return false;
            }
        }
        return true;
    }
    private int snmpIndentLevel;
}