package com.wytehat.btlogger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Ordering for the tracked item list.
 *
 * Default order is newest sighting first. Items that have not been seen for
 * a long time - or that carry no sighting timestamp at all - are pushed to
 * the bottom and stay there in both sort directions, so the reverse toggle
 * never buries a live item under a pile of stale ones.
 */
final class DeviceSort {

    /** A device unseen for longer than this sinks to the bottom. */
    static final long STALE_AFTER_MS = 24L * 60L * 60L * 1000L;

    private DeviceSort() {
    }

    /**
     * Last moment the device was actually observed. Deliberately ignores
     * updatedAt, which also moves when the user edits a name or colour.
     */
    static long lastSeen(DeviceRecord record) {

        if (record == null) {
            return 0L;
        }

        long seen = record.lastRssiAt;

        if (record.connectedAt > seen) {
            seen = record.connectedAt;
        }

        if (record.disconnectedAt > seen) {
            seen = record.disconnectedAt;
        }

        return seen;
    }

    static boolean isStale(DeviceRecord record, long now) {

        long seen = lastSeen(record);

        return seen <= 0L ||
            now - seen > STALE_AFTER_MS;
    }

    /**
     * @param reverse false = newest first (default), true = oldest first.
     */
    static List<DeviceRecord> sorted(List<DeviceRecord> rows, boolean reverse) {

        ArrayList<DeviceRecord> fresh = new ArrayList<DeviceRecord>();
        ArrayList<DeviceRecord> stale = new ArrayList<DeviceRecord>();

        if (rows == null) {
            return fresh;
        }

        long now = System.currentTimeMillis();

        for (int i = 0; i < rows.size(); i++) {

            DeviceRecord record = rows.get(i);

            if (record == null) {
                continue;
            }

            if (isStale(record, now)) {
                stale.add(record);
            } else {
                fresh.add(record);
            }
        }

        Comparator<DeviceRecord> newestFirst =
            new Comparator<DeviceRecord>() {

                public int compare(DeviceRecord left, DeviceRecord right) {

                    long a = lastSeen(left);
                    long b = lastSeen(right);

                    if (a == b) {
                        return left.displayName()
                            .compareToIgnoreCase(right.displayName());
                    }

                    return a > b ? -1 : 1;
                }
            };

        Collections.sort(fresh, newestFirst);
        Collections.sort(stale, newestFirst);

        if (reverse) {
            Collections.reverse(fresh);
            Collections.reverse(stale);
        }

        ArrayList<DeviceRecord> result =
            new ArrayList<DeviceRecord>(fresh.size() + stale.size());

        result.addAll(fresh);

        /*
         * Stale entries are appended last in both directions.
         */
        result.addAll(stale);

        return result;
    }
}
