package com.cookpad.puree.outputs;

import com.cookpad.puree.PureeLogger;
import com.cookpad.puree.async.AsyncResult;
import com.cookpad.puree.internal.PureeVerboseRunnable;
import com.cookpad.puree.internal.RetryableTaskRunner;
import com.cookpad.puree.storage.EnhancedPureeStorage;
import com.cookpad.puree.storage.Records;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;

import javax.annotation.ParametersAreNonnullByDefault;

@ParametersAreNonnullByDefault
public abstract class PureeBufferedOutput extends PureeOutput {

    RetryableTaskRunner flushTask;

    ScheduledExecutorService executor;

    public PureeBufferedOutput() {
    }

    @Override
    public void initialize(PureeLogger logger) {
        super.initialize(logger);
        executor = logger.getExecutor();
        flushTask = new RetryableTaskRunner(new Runnable() {
            @Override
            public void run() {
                flush();
            }
        }, conf.getFlushIntervalMillis(), conf.getMaxRetryCount(), executor);
    }

    @Override
    public void receive(final String jsonLog) {
        executor.execute(new PureeVerboseRunnable(new Runnable() {
            @Override
            public void run() {
                String filteredLog = applyFilters(jsonLog);
                if (filteredLog != null) {
                    storage.insert(type(), filteredLog);
                }
            }
        }));

        flushTask.tryToStart();
    }

    @Override
    public void flush() {
        executor.execute(new PureeVerboseRunnable(new Runnable() {
            @Override
            public void run() {
                flushSync();
            }
        }));
    }

    public void flushSync() {
        if (!storage.lock()) {
            flushTask.retryLater();
            return;
        }
        purgeRecordsFromStorage();
        final Records records = getRecordsFromStorage();

        if (records.isEmpty()) {
            storage.unlock();
            flushTask.reset();
            return;
        }

        final List<String> jsonLogs = records.getJsonLogs();

        emit(jsonLogs, new AsyncResult() {
            @Override
            public void success() {
                flushTask.reset();
                storage.delete(records);
                storage.unlock();
            }

            @Override
            public void fail() {
                flushTask.retryLater();
                storage.unlock();
            }
        });
    }

    private Records getRecordsFromStorage() {
        return storage.select(type(), conf.getLogsPerRequest());
    }

    public abstract void emit(List<String> jsonLogs, final AsyncResult result);

    private void purgeRecordsFromStorage() {
        if (!(storage instanceof EnhancedPureeStorage) || conf.getPurgeAgeMillis() == -1) {
            return;
        }

        ((EnhancedPureeStorage) storage).delete(type(), conf.getPurgeAgeMillis());
    }

    public void emit(String jsonLog) {
        // do nothing
    }
}


@@ -2823,13 +2823,11 @@
 s() 
-== -1
+%3C 0
 ) %7B%0A

Fix purgeAgeLogMillis validity check