package org.deepsymmetry.beatlink;

import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * Represents rekordbox metadata (title, artist, etc.) about tracks loaded into players on a DJ Link network.
 *
 * @author James Elliott
 */
public class TrackMetadata {

    /**
     * When this metadata was received.
     */
    private final long timestamp;

    /**
     * The player/device number which loaded the track described by the metadata.
     */
    private final int deviceNumber;

    /**
     * The raw packet data containing the metadata.
     */
    private final List<byte[]> rawFields;

    /**
     * Get the raw packet data, to analyze fields that have not yet been reliably understood.
     *
     * @return the raw bytes we received from the CDJ when asked for metadata
     */
    public List<byte[]> getRawFields() {
        List<byte[]> result = new LinkedList<byte[]>();
        for (byte[] field: rawFields) {
            byte[] copy = new byte[field.length];
            System.arraycopy(field, 0, copy, 0, field.length);
            result.add(copy);
        }
        return result;
    }

    /**
     * The title of the track.
     */
    private final String title;

    /**
     * The artist that created the track.
     */
    private final String artist;

    /**
     * The length, in seconds, of the track.
     */
    private final int length;

    /**
     * The album on which the track was released.
     */
    private final String album;

    /**
     * The comment assigned to the track.
     */
    private final String comment;

    /**
     * The dominant key of the track.
     */
    private final String key;

    /**
     * The musical genre of the track.
     */
    private final String genre;

    /**
     * The label of the track.
     */
    private final String label;

    /**
     * Extracts the value of a string field from the metadata.
     *
     * @param field the field known to contain a string value.
     * @return the value present in that field.
     *
     * @throws UnsupportedEncodingException if there is a problem interpreting the metadata
     */
    private String extractString(byte[] field) throws UnsupportedEncodingException {
        if (field.length > 46) {
            int length = (int) Util.bytesToNumber(field, 42, 4);
            if (length > 0) {
                return new String(field, 46, (2 * (length - 1)), "UTF-16");
            }
        }
        return "";
    }

    /**
     * Constructor sets all the immutable interpreted fields based on the received content.
     *
     * @param device the device number from which the metadata was received
     * @param fields the metadata that was received
     *
     * @throws UnsupportedEncodingException if there is a problem interpreting the metadata
     */
    public TrackMetadata(int device, List<byte[]> fields) throws UnsupportedEncodingException {
        timestamp = System.currentTimeMillis();
        deviceNumber = device;
        rawFields = fields;

        Iterator<byte[]> iterator = fields.iterator();
        iterator.next();  // TODO: Consider extracting artwork
        iterator.next();
        title = extractString(iterator.next());
        artist = extractString(iterator.next());
        album = extractString(iterator.next());
        length = (int)Util.bytesToNumber(iterator.next(), 32, 4);
        iterator.next();
        comment = extractString(iterator.next());
        key = extractString(iterator.next());
        iterator.next();
        iterator.next();
        genre = extractString(iterator.next());
        label = extractString(iterator.next());
    }

    @Override
    public String toString() {
        return "Track Metadata: Title: " + title + ", Artist: " + artist + ", Album: " + album +
                ", Length: " + length + ", Comment: " + comment + ", Key: " + key +
                ", Genre: " + genre + ", Label: " + label;
    }
}

@@ -3990,11 +3990,1335 @@
 l;%0A    %7D
+%0A%0A    /**%0A     * Get the timestamp recording when the metadata was received.%0A     *%0A     * @return the nanosecond timestamp at which we received this update%0A     */%0A    public long getTimestamp() %7B%0A        return timestamp;%0A    %7D%0A%0A    /**%0A     * Get the artist of the track.%0A     *%0A     * @return the track artist%0A     */%0A    public String getArtist() %7B%0A        return artist;%0A    %7D%0A%0A    /**%0A     * Get the comment assigned to the track.%0A     *%0A     * @return the track comment%0A     */%0A    public String getComment() %7B%0A        return comment;%0A    %7D%0A%0A    /**%0A     * Get the genre of the track.%0A     *%0A     * @return the track genre%0A     */%0A    public String getGenre() %7B%0A        return genre;%0A    %7D%0A%0A    /**%0A     * Get the musical key of the track.%0A     *%0A     * @return the track key%0A     */%0A    public String getKey() %7B%0A        return key;%0A    %7D%0A%0A    /**%0A     * Get the label assigned the track.%0A     *%0A     * @return the track label%0A     */%0A    public String getlabel() %7B%0A        return label;%0A    %7D%0A%0A    /**%0A     * Get the length of the track, in seconds.%0A     *%0A     * @return the track length in seconds.%0A     */%0A    public int getLength() %7B%0A        return length;%0A    %7D%0A%0A    /**%0A     * Get the title of the track.%0A     *%0A     * @return the track title%0A     */%0A    public String getTitle() %7B%0A        return title;%0A    %7D
 %0A%7D%0A

Add getters for metadata fields.