package ru.yandex.webmaster3.worker.serplinks;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.webmaster3.storage.util.yt.YtException;
import ru.yandex.webmaster3.storage.util.yt.lock.CypressProvider;

/**
 * @author avhaliullin
 */
public class SerpLinksProgressTracker {
    private static final Logger log = LoggerFactory.getLogger(SerpLinksProgressTracker.class);
    private static final String ZK_NODE_PATH = "/serplinks/changes";
    private static final ObjectMapper OM = new ObjectMapper();

    private final CypressProvider cypressProvider;
    private CypressProvider.Stat stat = new CypressProvider.Stat();
    private long currentVersion = 0;
    private ProgressRecord currentRecord = null;

    public SerpLinksProgressTracker(CypressProvider cypressProvider) throws Exception {
        this.cypressProvider = cypressProvider;
        String currentData = null;
        try {
            currentData = cypressProvider.getData().storingStatIn(stat).forPath(ZK_NODE_PATH);
        } catch (YtException e) {
            //ignored
        }
        if (currentData == null) {
            log.warn("No serplinks progress record found! Creating one...");
            this.currentRecord = new ProgressRecord();
            cypressProvider.create().forPath(ZK_NODE_PATH, OM.writeValueAsString(currentRecord));
        } else {
            this.currentVersion = stat.getVersion();
            this.currentRecord = OM.readValue(currentData, ProgressRecord.class);
        }
    }

    public ProgressRecord getRecord() throws Exception {
        return currentRecord;
    }

    public ProgressRecord startNewFile(long timestamp) throws Exception {
        return update(new ProgressRecord(timestamp, -1, false));
    }

    public ProgressRecord incrementOffset() throws Exception {
        return update(new ProgressRecord(currentRecord.fileTimestamp, currentRecord.offset + 1, false));
    }

    public ProgressRecord fileExhausted() throws Exception {
        return update(new ProgressRecord(currentRecord.fileTimestamp, currentRecord.offset, true));
    }

    private ProgressRecord update(ProgressRecord newRecord) throws Exception {
        String newData = OM.writeValueAsString(newRecord);
        stat = cypressProvider.setData().withVersion(currentVersion).forPath(ZK_NODE_PATH, newData);
        currentVersion = stat.getVersion();
        currentRecord = newRecord;
        return currentRecord;
    }

    public static class ProgressRecord {
        private long fileTimestamp;
        private int offset;
        private boolean processed;

        public ProgressRecord() {
            this(0L, -1, true);
        }

        public ProgressRecord(long fileTimestamp, int offset, boolean processed) {
            this.fileTimestamp = fileTimestamp;
            this.offset = offset;
            this.processed = processed;
        }

        public long getFileTimestamp() {
            return fileTimestamp;
        }

        public void setFileTimestamp(long fileTimestamp) {
            this.fileTimestamp = fileTimestamp;
        }

        public int getOffset() {
            return offset;
        }

        public void setOffset(int offset) {
            this.offset = offset;
        }

        public boolean isProcessed() {
            return processed;
        }

        public void setProcessed(boolean processed) {
            this.processed = processed;
        }
    }
}
