package ru.yandex.wmtools.common.data.multidbpager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.common.util.xml.XmlConvertable;
import ru.yandex.wmtools.common.data.wrappers.IntegerWrapper;

import java.util.Arrays;

/**
 * Используется для формирования запроса на выборку данного фрагмента данных и
 * для отбражения информации о пейджере в том случае, когда таблица находится в нескольких базах данных (например,
 * таблица секционирована по пользователю, и каждая база данных хранит часть пользователей.
 *
 * @author baton
 */
public class MultiDbPager<T> implements XmlConvertable {
    private static final Logger log = LoggerFactory.getLogger(MultiDbPager.class);

    private int[] currentDbIndexArray;
    private int[] nextDbIndexArray = null;

    private final SortStrategy<T> sortStrategy;

    private int pageSize;
    private final boolean showAll;
    private Integer totalCount = null;

    public MultiDbPager(final int pageSize, final int dbCount, final SortStrategy<T> sortStrategy) {
        this(pageSize, new int[dbCount], sortStrategy);
    }

    public MultiDbPager(final int pageSize, int[] currentDbIndexArray, final SortStrategy<T> sortStrategy) {
        this(pageSize, currentDbIndexArray, false, sortStrategy);
    }

    public MultiDbPager(final int pageSize, int[] currentDbIndexArray, final boolean showAll, final SortStrategy<T> sortStrategy) {
        if (!(pageSize > 0)) {
            throw new IllegalArgumentException("Wrong page totalPageCount value: " + pageSize);
        }
        this.pageSize = pageSize;
        this.showAll = showAll;
        this.sortStrategy = sortStrategy;
        this.currentDbIndexArray = currentDbIndexArray;
    }

    private int getTotalPageCount() {
        return 1 + Math.max(0, totalCount - 1) / pageSize;
    }

    public int[] getCurrentDbIndexArray(int dbCount) {
        int[] res = new int[dbCount];
        for (int i = 0; i < dbCount; i++) {
            res[i] = 0;
        }

        if ((currentDbIndexArray != null) && (currentDbIndexArray.length == dbCount)) {
            System.arraycopy(currentDbIndexArray, 0, res, 0, dbCount);
        }

        return res;
    }

    public boolean isShowAll() {
        return showAll;
    }

    private Integer getPageNum() {
        if (currentDbIndexArray == null) {
            return 0;
        } else {
            int curCount = 0;
            for (int currentDbIndex : currentDbIndexArray) {
                curCount += currentDbIndex;
            }
            if (((curCount % pageSize) == 0)) {
                return (curCount / pageSize);
            } else {
                return null;
            }
        }
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setNextDbIndexArray(int[] nextDbIndexArray) {
        this.nextDbIndexArray = nextDbIndexArray;
    }

    public SortStrategy<T> getSortStrategy() {
        return sortStrategy;
    }

    public void setTotalCount(final Integer totalCount) {
        this.totalCount = totalCount;
        if (totalCount != null) {
            if (showAll) {
//                pageSize = Math.max(totalCount, 1);
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("New multiDb pager params: pageSize=" +
                    pageSize + "; totalCount = " + totalCount);
        }
    }

    public int[] getNextDbIndexArray() {
        return Arrays.copyOf(nextDbIndexArray, nextDbIndexArray.length);
    }

    @Override
    public void toXml(StringBuilder result) {
        if (totalCount <= pageSize) {
            // no pager, because we have only 1 page.
            return;
        }

        result.append("<pager ");
        result.append("total-count=\"").append(totalCount).append("\" ");

        // 1 2 _3_ 4 5 6 7
        // 2 3 4 _5_ 6 7 8 // for PL=3
        result.append("page-size=\"").append(pageSize).append("\" ");
        result.append("show-all=\"").append(showAll ? "on" : "").append("\" ");
        result.append("total-page-count=\"").append(getTotalPageCount());
        result.append("\">");

        if (totalCount == null || totalCount == 0) {
            return; // print nothing
        }

        if (currentDbIndexArray != null) {
            result.append("<current>");
            int idx = 0;
            for (int dbIndex : currentDbIndexArray) {
                new IntegerWrapper("dbindex" + idx++, dbIndex).toXml(result);
            }
            result.append("</current>");
        }

        if (nextDbIndexArray != null) {
            // count, if we have last page
            int count = 0;
            for (int dbIndex : nextDbIndexArray) {
                count += dbIndex;
            }
            if (count < totalCount) {
                result.append("<next>");
                int idx = 0;
                for (int dbIndex : nextDbIndexArray) {
                    new IntegerWrapper("dbindex" + idx++, dbIndex).toXml(result);
                }
                result.append("</next>");
            }
        }

        Integer pageNum = getPageNum();
        if (pageNum != null) {
            result.append("<page num=\"").append(pageNum).append("\"/>");
        }

        result.append("</pager>");
    }
}
