package org.roklib.urifragmentrouting.parameter;

import org.roklib.urifragmentrouting.exception.ParameterValueConversionException;
import org.roklib.urifragmentrouting.parameter.converter.ParameterValueConverter;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This URI parameter handles parameter values consisting of two parts: a numerical value (interpreted as a number of
 * type Long) and a textual suffix. This is useful if you want to add an id (e. g. the primary key of some item)
 * including a human-readable textual description of the referred item into a URI fragment. Consider, for example, a
 * blogging software where individual blog posts are referred in the URI fragment by their database id. In order to give
 * the users more context about the referred blog posts, a post's title can be added to the post id. For example:
 * <p>
 * <tt>http://www.example.com/blog#!posts/67234-my-first-blog-post</tt>
 * <p>
 * For these use cases you can use this parameter type. It converts the parameter's String value into an object of type
 * {@link IdWithText}. This object contains the number as a Long value and the remaining text as a String. In the
 * example above, the object would contain <tt>id=67234</tt> and <tt>text="-my-first-blog-post"</tt>.
 */
public class SingleLongWithIgnoredTextUriParameter extends AbstractSingleUriParameter<SingleLongWithIgnoredTextUriParameter.IdWithText> {
    private static final long serialVersionUID = 7990237721421647271L;

    public SingleLongWithIgnoredTextUriParameter(String parameterName) {
        super(parameterName, IdWithTextParameterValueConverter.INSTANCE);
    }

    /**
     * Defines a data object which combines two values: a numerical ID together with a text. This is used as the domain
     * type for values of {@link SingleLongWithIgnoredTextUriParameter}.
     */
    public interface IdWithText {
        Long getId();

        String getText();

        void setId(Long id);

        void setText(String text);
    }

    /**
     * Implementation of interface {@link IdWithText}. Two objects of this class are considered equal if their ids
     * match. The text is ignored.
     */
    public static class IdWithTextImpl implements IdWithText {
        private Long id;
        private String text;

        public IdWithTextImpl() {
        }

        public IdWithTextImpl(Long id, String text) {
            this.id = id;
            this.text = text;
        }

        @Override
        public Long getId() {
            return id;
        }

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

        @Override
        public void setId(Long id) {
            this.id = id;
        }

        @Override
        public void setText(String text) {
            this.text = text;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (!(obj instanceof IdWithTextImpl)) {
                return false;
            }
            IdWithTextImpl other = (IdWithTextImpl) obj;
            return id != null && other.id.equals(id);
        }

        @Override
        public int hashCode() {
            return id == null ? 0 : id.hashCode();
        }
    }


    /**
     * Converter class for converting a String into an object of type {@link IdWithText}. The converter tries to match
     * an input String against the regular expression {@code ^(\d+)(.*)}. This will match any number with an arbitrary
     * textual suffix. An example for such a String would be
     * <p>
     * <tt>50923-my-first-blog-post</tt>
     */
    public static class IdWithTextParameterValueConverter implements ParameterValueConverter<IdWithText> {
        private final static Pattern PATTERN = Pattern.compile("^(\\d+)(.*)");
        public final static IdWithTextParameterValueConverter INSTANCE = new IdWithTextParameterValueConverter();

        @Override
        public String convertToString(IdWithText value) {
            if (value == null || value.getId() == null) {
                return "";
            }

            return value.getId().toString() + (value.getText() == null ? "" : value.getText());
        }

        @Override
        public IdWithText convertToValue(final String valueAsString) throws ParameterValueConversionException {
            final Matcher m = PATTERN.matcher(valueAsString);
            final IdWithTextImpl result = new IdWithTextImpl();
            if (m.find()) {
                try {
                    result.setId(Long.valueOf(m.group(1)));
                } catch (final NumberFormatException e) {
                    throw new ParameterValueConversionException(e);
                }
                result.setText(m.group(2));
                return result;
            } else {
                throw new ParameterValueConversionException();
            }
        }
    }
}

@@ -1545,16 +1545,22 @@
 rameter(
+final 
 String p
@@ -1571,24 +1571,24 @@
 eterName) %7B%0A
-
         supe
@@ -2384,16 +2384,22 @@
 mpl(
+final 
 Long id,
  Str
@@ -2394,16 +2394,22 @@
 Long id,
+ final
  String 
@@ -2689,32 +2689,38 @@
 blic void setId(
+final 
 Long id) %7B%0A     
@@ -2789,32 +2789,38 @@
 ic void setText(
+final 
 String text) %7B%0A 
@@ -2907,16 +2907,22 @@
  equals(
+final 
 Object o
@@ -3109,16 +3109,22 @@
         
+final 
 IdWithTe
@@ -4022,32 +4022,32 @@
       @Override%0A
-
         public S
@@ -4068,16 +4068,22 @@
 oString(
+final 
 IdWithTe

Add final keyword where appropriate