package de.cosmicsand.webtools.path;

import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.regex.Pattern.compile;
import static org.apache.commons.lang.StringUtils.isEmpty;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class Path implements Comparable<Path> {

    // needs to be defined before the very first constructor invocation
    protected static final Pattern SYNTAX_PATTERN = compile("(/[^/]*)*");

    public static final Path ROOT = new Path();

    private static final String ERR_MESS_SYNTAX_PATTERN = "If not empty the given path is required to follow the pattern '/your/path'. Current value: '%s'";

    public final String rawPath;

    private List<PathAtom> atoms;

    public Path(String rawPath) {
        this.rawPath = isEmpty(rawPath) ? "/" : rawPath;
        if (!SYNTAX_PATTERN.matcher(this.rawPath).matches())
            throw new URLPathException(format(ERR_MESS_SYNTAX_PATTERN, rawPath));
    }

    public Path() {
        this("");
    }

    public Path(PathAtom... pathAtoms) {
        StringBuilder pathBuilder = new StringBuilder();
        for (PathAtom atom : pathAtoms)
            pathBuilder.append(atom.getOuterName());
        rawPath = pathBuilder.toString();
        atoms = asList(pathAtoms);
    }

    public Path(Path path) {
        if (path == null)
            rawPath = ROOT.rawPath;
        else
            rawPath = path.rawPath;
    }

    @Override
    public String toString() {
        return rawPath.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Path)
            return rawPath.toString().equals(((Path) obj).rawPath.toString());
        return false;
    }

    @Override
    public int hashCode() {
        return rawPath.toString().hashCode();
    }

    @Override
    public int compareTo(Path other) {
        return rawPath.toString().compareTo(other.rawPath.toString());
    }

    public List<PathAtom> getAtoms() {
        if (ROOT.equals(this))
            atoms = emptyList();
        if (atoms == null)
            extractAtoms();
        return atoms;
    }

    private void extractAtoms() {
        atoms = new ArrayList<PathAtom>();
        String[] split = rawPath.substring(1).split("/");
        for (String rawAtom : split)
            atoms.add(atoms.size(), new PathAtom(rawAtom));
    }

    public Path add(Path path) {
        Path helperPath = new Path(path);
        StringBuilder resultPath = new StringBuilder(this.rawPath);
        resultPath.append(helperPath.rawPath);
        cleanupObsoleteSlashes(resultPath);
        return new Path(resultPath.toString());
    }

    private void cleanupObsoleteSlashes(StringBuilder dirtyPath) {
        if (dirtyPath.length() > 1 && dirtyPath.charAt(1) == '/')
            dirtyPath.replace(0, 1, "");
    }

    public Path merge(Path path) {
        if (!this.equals(path))
            this.add(path);
        return this;
    }
}

@@ -1142,24 +1142,166 @@
 athAtoms) %7B%0A
+        rawPath = buildRawPath(pathAtoms);%0A        atoms = asList(pathAtoms);%0A    %7D%0A%0A    private String buildRawPath(PathAtom... pathAtoms) %7B%0A
         Stri
@@ -1341,24 +1341,24 @@
 gBuilder();%0A
-
         for 
@@ -1443,32 +1443,29 @@
 );%0A        r
-awPath =
+eturn
  pathBuilder
@@ -1481,43 +1481,8 @@
 ();%0A
-        atoms = asList(pathAtoms);%0A
     
@@ -1698,27 +1698,16 @@
  rawPath
-.toString()
 ;%0A    %7D%0A
@@ -1821,27 +1821,16 @@
 rawPath.
-toString().
 equals((
@@ -1844,35 +1844,24 @@
 obj).rawPath
-.toString()
 );%0A        r
@@ -1945,27 +1945,16 @@
 rawPath.
-toString().
 hashCode
@@ -2044,19 +2044,8 @@
 ath.
-toString().
 comp
@@ -2059,35 +2059,24 @@
 ther.rawPath
-.toString()
 );%0A    %7D%0A%0A  

clean up implementation