package com.atlassian.bitbucket.mesh.git.builder.foreachref;

import com.atlassian.bitbucket.mesh.git.ref.Tag;

import javax.annotation.Nonnull;

/**
 * A reusable component for parsing {@link Tag tags} from a {@code String}.
 */
public class ForEachTagParser implements ForEachRefParser<Tag> {

    /**
     * Format for {@code git for-each-ref}. This is the format that is expected by {@link #parse(String)}.
     * <p>
     * What each field means varies depending on the tag type:
     * <ul>
     *     <li>Annotated/signed tags
     *     <ul>
     *         <li>{@code refname} -&gt; fully-qualified tag name (ID)</li>
     *         <li>{@code objectname} -&gt; tag hash</li>
     *         <li>{@code *objectname} -&gt; commit hash (dereferences the tag to get the hash of the head commit)</li>
     *     </ul>
     *     </li>
     *     <li>Lightweight tags
     *     <ul>
     *         <li>{@code refname} -&gt; fully-qualified tag name (ID)</li>
     *         <li>{@code objectname} -&gt; commit hash</li>
     *         <li>{@code *objectname} -&gt; not present</li>
     *     </ul>
     *     </li>
     * </ul>
     *
     * @see <a href="http://git-scm.com/docs/git-for-each-ref/2.2.0">git-for-each-ref</a>
     */
    public static final String FORMAT = ForEachRefUtils.normalize("%(refname)|%(objectname)|%(*objectname)");
    public static final ForEachTagParser INSTANCE = new ForEachTagParser();

    private ForEachTagParser() {
    }

    @Nonnull
    @Override
    public String getFormat() {
        return FORMAT;
    }

    /**
     * Parses a string and returns a {@link Tag}.
     *
     * @param line a single line of output from {@code git for-each-ref}
     * @return a @{link Tag}, or {@code null} if the line could not be parsed
     */
    @Override
    public Tag parse(@Nonnull String line) {
        String[] pieces = line.split(ForEachRefUtils.SEPARATOR_CHAR);

        Tag.Builder builder = new Tag.Builder()
                .id(pieces[0]);
        if (pieces.length == 3) {
            //All three fields are set; it's an annotated tag or a signed tag
            builder.hash(pieces[1]).latestCommit(pieces[2]);
        } else if (pieces.length == 2) {
            //*objectname is not present; it's a lightweight tag
            builder.latestCommit(pieces[1]);
        } else {
            return null;
        }

        return builder.build();
    }
}
