/*
 * 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.netbeans.modules.java.guards;

import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import org.netbeans.api.editor.guards.GuardedSection;
import org.openide.util.NbBundle;

/**
 *
 * @author Jan Pokorsky
 */
final class JavaGuardedReader {

    /** The prefix of all magic strings */
    final static String MAGIC_PREFIX = "//GEN-"; // NOI18N
    
    Pattern magicsAsRE;
    
    private static final int LONGEST_ITEM = 10;

    /**
     * There are three possible ways how the comments defining the guarded
     * sections can be processed during reading through the reader:
     * 1. Keep the comments. They will be visible to the user in source editor.
     * 2. Replace the comments with spaces to hide them from user but to preserve
     *    overall length and positions.
     * 3. Remove the comments completely.
     * 
     * Option #3 causes that offsets inside the editor differ from the offsets on disk,
     * which then breaks many clients that create PositionRefs for a closed file and then
     * use it for an opened file, and vice versa.
     * 
     * Default is #2.
     */
    private static boolean KEEP_GUARD_COMMENTS    // not final only for tests
            = getPresetValue("KEEP_GUARD_COMMENTS", false); // NOI18N

    /** The list of the SectionsDesc. */
    private final LinkedList<SectionDescriptor> list;

    private final JavaGuardedSectionsProvider provider;
    
    /** Creates a new instance of JavaGuardedReader */
    public JavaGuardedReader(JavaGuardedSectionsProvider provider) {
        list = new LinkedList<SectionDescriptor>();
        this.provider = provider;
    }
    
    public List<GuardedSection> getGuardedSections() {
        return fillSections(list);
    }
    
    public char[] translateToCharBuff(char[] readBuff) {
        char[] charBuff = new char[readBuff.length];
        // points to first unused cell in charBuff
        int charBuffPtr = 0;
        int stop = readBuff.length - 1;

        // read char
        int c;
        // ptr to first not processed char in readBuff
        int i = 0;
        // points to a character right after a newline
        int lastNewLine = 0;

        // final automata
        int fatpos = 0;
        final int MAGICLEN = MAGIC_PREFIX.length();


        //process newlines so only '\n' appears in the charBuff
        //count all kinds of newlines - most used will be used on save
        while (i < stop) {
            c = readBuff[i];
            if (c == '\n') {
                lastNewLine = charBuffPtr;
            }
            charBuff[charBuffPtr++] = readBuff[i++];

            switch (fatpos) {
            case 0:
                if (c == '/') {
                    fatpos++;
                } else {
                    fatpos = 0;
                }
                break;

            case 1:
                if (c == '/') {
                    fatpos++;
                } else {
                    fatpos = 0;
                }
                break;

            case 2:
                if (c == 'G') {
                    fatpos++;
		    } else if (c == '/') {
			fatpos = 2; // what if /////GEN-xxx?
                } else {
                    fatpos = 0;
                }
                break;

            case 3:
                if (c == 'E') {
                    fatpos++;
                } else {
                    fatpos = 0;
                }
                break;

            case 4:
                if (c == 'N') {
                    fatpos++;
                } else {
                    fatpos = 0;
                }
                break;

            case 5:
                if (c == '-') {
                    fatpos++;
                } else {
                    fatpos = 0;
                }
                break;

            default:
                fatpos = 0;
            }

            // "//GEN-" was reached at this time
            if (fatpos == MAGICLEN) {
                fatpos = 0;
                Pattern magics = getMagicsAsRE();
                int searchLen = Math.min(LONGEST_ITEM, readBuff.length - i);
                CharBuffer chi = CharBuffer.wrap(readBuff, i, searchLen);
                Matcher matcher = magics.matcher(chi);
                if (matcher.find()) {
                    String match = matcher.group();

                    charBuffPtr -= MAGICLEN;
                    i += match.length();
                    int toNl = toNewLine(i, readBuff);
                    int sectionSize = MAGICLEN+match.length()+toNl;
                    
//                    if (!justFilter) {
//                        System.out.println("## MATCH: '" + match.substring(0, match.length() - 1) + "'");
                        SectionDescriptor desc = new SectionDescriptor(
                                GuardTag.valueOf(match.substring(0, match.length() - 1)), //XXX catch IAE
                                String.valueOf(readBuff, i, toNl),
                                lastNewLine + 1,
                                charBuffPtr + sectionSize
                                );
//                                new SectionDescriptor(GuardTag.valueOf(match.substring(0, match.length() - 1))); //XXX catch IAE
//                        desc.begin = lastNewLine;
//                        desc.end = charBuffPtr + sectionSize + 1;
//                        desc.name = new String(readBuff, i, toNl);
                        list.add(desc);
//                    }
                    if (KEEP_GUARD_COMMENTS) { // keep guard comment (content unchanged)
                        i -= match.length();
                        charBuffPtr += MAGICLEN;
                    } else {
                        i += toNl;
                        Arrays.fill(charBuff,charBuffPtr,charBuffPtr+sectionSize,' ');
                        charBuffPtr+=sectionSize;
                    }
                }
            }
        }

        if (i == stop) {
//            c = readBuff[i];
//            switch(c) {
//                case (int) '\n':
//
//                    newLineTypes[NewLine.N.ordinal()]++;
//
//                    charBuff[charBuffPtr++] = '\n';
//
//                    break;
//                case (int) '\r':
//
//                    newLineTypes[NewLine.R.ordinal()]++;
//
//                    charBuff[charBuffPtr++] = '\n';
//
//                    break;
//                default:
//
                    charBuff[charBuffPtr++] = readBuff[i++];
//            }
        }

        // repair last SectionDesc
        if (/*!justFilter && */(list.size() > 0)) {
            SectionDescriptor desc = (SectionDescriptor) list.getLast();
            if (desc.getEnd() > charBuffPtr) {
                desc.setEnd(charBuffPtr);
            }
        }
        
        char[] res;
        if (charBuffPtr != charBuff.length) {
            res = new char[charBuffPtr];
            System.arraycopy(charBuff, 0, res, 0, charBuffPtr);
        } else {
            res = charBuff;
        }
        return res;
    }

    /** @return searching engine for magics */
    final Pattern getMagicsAsRE() {
        if (magicsAsRE == null) {
            magicsAsRE = Pattern.compile(makeOrRegexp());
        }
        return magicsAsRE;
    }

    /** Makes or regular expression for magics */
    final String makeOrRegexp() {
        StringBuilder sb = new StringBuilder(100);
//        final int len = MAGIC_PREFIX.length();
        for (GuardTag t: GuardTag.values()) {
            sb.append(t.name() + ':');
            sb.append('|');
        }

        return sb.substring(0, sb.length() - 1);
    }

    /** Searches for newline from i */
    static int toNewLine(int i, char[] readBuff) {
        int c;
        int counter = i;
        final int len = readBuff.length;
        while (counter < len) {
            c = readBuff[counter++];
            if (c == '\r' || c == '\n') {
                counter--;
                break;
            }
        }

        return counter - i;
    }

    /** Takes the section descriptors from the GuardedReader and
    * fills the table 'sections', also marks as guarded all sections
    * in the given document.
    * @param is Where to take the guarded section descriptions.
    * @param doc Where to mark guarded.
    */
    List<GuardedSection> fillSections(List<SectionDescriptor> descs) {
        SectionDescriptor descBegin = null;
        List<GuardedSection> sections = new ArrayList<GuardedSection>(descs.size());
        
        for (SectionDescriptor descCurrent: descs) {
            try {
                GuardedSection sect = null;
                switch (descCurrent.getType()) {
                case LINE:
                    sect = provider.createSimpleSection(
                            descCurrent.getName(),
                            descCurrent.getBegin(),
                            descCurrent.getEnd()
                            );
                    break;

                case BEGIN:
                case HEADER:
                case FIRST:
                    descBegin = descCurrent;
                    break;

                case HEADEREND:
                    if ((descBegin != null) &&
                            ((descBegin.getType() == GuardTag.HEADER) || (descBegin.getType() == GuardTag.FIRST)) &&
                            (descCurrent.getName().equals(descBegin.getName()))
                       ) {
                        descBegin.setEnd(descCurrent.getEnd());
                    }
                    else {
                        //SYNTAX ERROR - ignore it.
                        descBegin = null;
                    }
                    break;

                case END:
                case LAST:
                    if ((descBegin != null) && (descBegin.getName().equals(descCurrent.getName()))) {
                        if ((descBegin.getType() == GuardTag.BEGIN) && (descCurrent.getType() == GuardTag.END)) {
                            // simple section
                            sect = provider.createSimpleSection(
                                    descCurrent.getName(),
                                    descBegin.getBegin(), descCurrent.getEnd()
                                    );
                            break;
                        }
                        if (((descBegin.getType() == GuardTag.FIRST) && (descCurrent.getType() == GuardTag.LAST)) ||
                                ((descBegin.getType() == GuardTag.HEADER) && (descCurrent.getType() == GuardTag.END))) {
                                // interior section
                                sect = provider.createInteriorSection(
                                        descCurrent.getName(),
                                        descBegin.getBegin(), descBegin.getEnd(),
                                        descCurrent.getBegin(), descCurrent.getEnd()
                                        );
                            break;
                        }
                    }
                    //SYNTAX ERROR - ignore it.
                    descBegin = null;
                    break;
                }

                if (sect != null) {
                    sections.add(sect);
                }
            } catch (BadLocationException ex) {
                Logger.getLogger(JavaGuardedReader.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage(), ex);
            }
        }
        
        return sections;
    }
    
//    static String magic(GuardTag tag) {
//        return MAGIC_PREFIX + tag.name() + ':';
//    }

    private static boolean getPresetValue(String key, boolean defaultValue) {
        try {
            String s = NbBundle.getMessage(JavaGuardedReader.class, key);
            return "true".equals(s.toLowerCase()); // NOI18N
        } catch( MissingResourceException ex) { // ignore
        }
        return defaultValue;
    }

    static boolean getKeepGuardedComments() {
        return KEEP_GUARD_COMMENTS;
    }

    static void setKeepGuardCommentsForTest(boolean keep) {
        KEEP_GUARD_COMMENTS = keep;
    }
}
