/*
 * Copyright (c) 2017-2019 XMLmind Software. All rights reserved.
 *
 * Author: Hussein Shafie
 *
 * This file is part of the XMLmind Assembly Processor project.
 * For conditions of distribution and use, see the accompanying legal.txt file.
 */
package com.xmlmind.xinclude;

import com.xmlmind.util.StringUtil;

/*TEST_FRAGID
import java.io.File;
import com.xmlmind.util.FileUtil;
import com.xmlmind.util.LoadText;
TEST_FRAGID*/

/*package*/ final class TextFragmentIdentifier {
    public final boolean isCharPosition;
    public final int startPosition;
    public final int endPosition;

    // -----------------------------------------------------------------------

    public TextFragmentIdentifier(boolean isCharPosition,
                                  int startPosition, int endPosition) {
        assert(startPosition >= 0 && endPosition >= startPosition);

        this.isCharPosition = isCharPosition;
        this.startPosition = startPosition;
        this.endPosition = endPosition;
    }

    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder();

        buffer.append(isCharPosition? "char=" : "line=");
        buffer.append(startPosition);
        if (endPosition > startPosition) {
            buffer.append(',');
            if (endPosition < Integer.MAX_VALUE) {
                buffer.append(endPosition);
            }
        }

        return buffer.toString();
    }

    public static TextFragmentIdentifier parse(String spec) {
        boolean isCharPosition;
        if (spec.startsWith("char=")) {
            isCharPosition = true;
            spec = spec.substring(5);
        } else if (spec.startsWith("line=")) {
            isCharPosition = false;
            spec = spec.substring(5);
        } else {
            return null;
        }

        int pos = spec.indexOf(';');
        if (pos >= 0) {
            // We do not support integrity-check.
            spec = spec.substring(0, pos);
        }

        String start, end;
        pos = spec.indexOf(',');
        if (pos < 0) {
            start = end = spec.trim();
            if (start.length() == 0) {
                // "line=" does not make sense.
                return null;
            }
        } else {
            start = spec.substring(0, pos).trim();
            end = spec.substring(pos+1).trim();
            // "line=," is OK.
        }

        int startPosition = -1;
        if (start.length() == 0) {
            startPosition = 0;
        } else {
            try {
                startPosition = Integer.parseInt(start);
            } catch (NumberFormatException ignored) {}
        }

        int endPosition = -1;
        if (end.length() == 0) {
            endPosition = Integer.MAX_VALUE;
        } else {
            try {
                endPosition = Integer.parseInt(end);
            } catch (NumberFormatException ignored) {}
        }

        if (startPosition < 0 || endPosition < startPosition) {
            return null;
        }

        return new TextFragmentIdentifier(isCharPosition,
                                          startPosition, endPosition);
    }

    public String getFragment(String text) {
        // Inefficient implementation.

        if (text.indexOf("\r\n") >= 0) {
            text = StringUtil.replaceAll(text, "\r\n", "\n");
        }
        
        int start = startPosition;
        int end = endPosition;

        if (isCharPosition) {
            int charCount = text.length();
            if (start >= charCount) {
                return null;
            }

            if (end > charCount) {
                end = charCount;
            }
            
            if (end == start) {
                return null;
            }

            return text.substring(start, end);
        } else {
            String[] lines = StringUtil.split(text, '\n');
            int lineCount = lines.length;

            if (start >= lineCount) {
                return null;
            }

            if (end > lineCount) {
                end = lineCount;
            }

            if (end == start) {
                return null;
            }

            StringBuilder buffer = new StringBuilder();

            for (int i = start; i < end; ++i) {
                if (i > start) {
                    buffer.append('\n');
                }
                buffer.append(lines[i]);
            }

            return buffer.toString();
        }
    }

    // -----------------------------------------------------------------------

    /*TEST_FRAGID

    public static void main(String[] args) throws Exception {
        if (args.length < 3) {
            System.err.println(
                "java com.xmlmind.xml.xinclude.TextFragmentIdentifier" +
                " out_text_file in_text_file fragid ... fragid");
            System.exit(1);
        }

        File outFile = new File(args[0]);
        File inFile = new File(args[1]);

        String text = LoadText.loadText(inFile, null, null,
                                        LoadText.ALL_ENCODING_DETECTORS);

        StringBuilder out = new StringBuilder();

        for (int i = 2; i < args.length; ++i) {
            String arg = args[i];
            out.append('"');
            out.append(arg);
            out.append('"');

            TextFragmentIdentifier fragid = TextFragmentIdentifier.parse(arg);
            out.append(" --> ");
            if (fragid != null) {
                out.append(fragid);
                String fragment = fragid.getFragment(text);
                if (fragment != null) {
                    out.append("\n{");
                    out.append(fragment);
                    out.append("}");
                }
            }
            out.append('\n');
        }

        FileUtil.saveString(out.toString(), outFile, "UTF-8");
    }

    TEST_FRAGID*/
}
