/*
* Orion Viewer - pdf, djvu, xps and cbz file viewer for android devices
*
* Copyright (C) 2011-2013 Michael Bogdanov & Co
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package universe.constellation.orion.viewer;
/**
* User: mike
* Date: 29.08.12
* Time: 12:58
*/
public class PageWalker {
public static enum DIR {
//X, Y, -X, -Y
X (1), Y(1), X_M(-1), Y_M(-1);
private final int delta;
DIR(int delta) {
this.delta = delta;
}
public DIR inverse() {
switch (this) {
case X : return X_M;
case X_M: return X;
case Y: return Y_M;
case Y_M: return Y;
}
return X;
}
public boolean isX() {
return this == X_M || this == X;
}
public boolean toLeftOrUp() {
return this == X_M || this == Y_M;
}
public boolean toRightOrDown() {
return this == X || this == Y;
}
}
public static enum WALK_ORDER {
ABCD (0, DIR.X, DIR.Y), ACBD (1, DIR.Y, DIR.X), BADC(2, DIR.X_M, DIR.Y), BDAC (3, DIR.Y, DIR.X_M);
private final DIR first;
private final DIR second;
WALK_ORDER(int code, DIR first, DIR second) {
this.first = first;
this.second = second;
}
public String code() {
return this.name();
}
public boolean isLeftToRight() {
return this == ABCD || this == ACBD;
}
};
private boolean doCentering = true;
private WALK_ORDER direction;
private SimpleLayoutStrategy layout;
public PageWalker(String direction, SimpleLayoutStrategy layout) {
WALK_ORDER [] values = WALK_ORDER.values();
this.direction = WALK_ORDER.ABCD;
for (int i = 0; i < values.length; i++) {
WALK_ORDER value = values[i];
if (value.code().equals(direction)) {
this.direction = value;
break;
}
}
this.layout = layout;
}
public boolean next(LayoutPosition info) {
return next(info, direction.first, direction.second);
}
public boolean prev(LayoutPosition info) {
return next(info, direction.first.inverse(), direction.second.inverse());
}
//true if should show prev/next page
private boolean next(LayoutPosition info, DIR firstDir, DIR secondDir) {
boolean isX = firstDir.isX();
OneDimension first = isX ? info.x : info.y;
OneDimension second = isX ? info.y : info.x;
boolean changeSecond = true;
int newFirstOffset = -1;
int newSecondOffset = -1;
for (int i = 1; i <= 2; i ++) {
OneDimension dimension = i == 1 ? first : second;
DIR dir = i == 1 ? firstDir : secondDir;
boolean inverseX = dir.isX() && !direction.isLeftToRight();
int offset = inverseX ? dimension.pageDimension - dimension.offset - dimension.screenDimension: dimension.offset;
dir = inverseX ? dir.inverse() : dir;
if (changeSecond) {
changeSecond = false;
int newOffsetStart = offset + dimension.screenDimension * dir.delta;
int newOffsetEnd = newOffsetStart + dimension.screenDimension - 1;
if (!inInterval(newOffsetStart, dimension) && !inInterval(newOffsetEnd, dimension)) {
changeSecond = true;
offset = reset(dir, dimension, true);
} else {
if (needAlign(dir) && (!inInterval(newOffsetStart, dimension) || !inInterval(newOffsetEnd, dimension))) {
offset = align(dir, dimension);
} else {
offset = newOffsetStart - dimension.overlap * dir.delta;
}
}
}
offset = inverseX ? dimension.pageDimension - offset - dimension.screenDimension: offset;
if (i == 1) {
newFirstOffset = offset;
} else {
newSecondOffset = offset;
}
}
if (!changeSecond) {
(isX ? info.x : info.y).offset = newFirstOffset;
second.offset = newSecondOffset;
}
return changeSecond;
}
private int reset(DIR dir, OneDimension dim, boolean doCentering) {
if (this.doCentering && doCentering) {
if (dim.pageDimension < dim.screenDimension) {
return (dim.pageDimension - dim.screenDimension) / 2;
}
}
if (dir.toRightOrDown() || dim.pageDimension <= dim.screenDimension || dim.screenDimension == 0) {
return 0;
} else {
if (!needAlign(dir)) {
return ((dim.pageDimension - dim.overlap) / (dim.screenDimension - dim.overlap)) * (dim.screenDimension - dim.overlap);
} else {
return dim.pageDimension - dim.screenDimension;
}
}
}
private int align(DIR dir, OneDimension dim) {
if (dir.toRightOrDown()) {
return dim.pageDimension - dim.screenDimension;
} else {
return 0;
}
}
private boolean needAlign(DIR dir) {
return dir.isX() && layout.getLayout() != 0 || (!dir.isX() && layout.getLayout() == 1);
}
private boolean inInterval(int value, OneDimension dim) {
return value >= 0 && value < dim.pageDimension;
}
public void reset(LayoutPosition info, boolean isNext, boolean doCentering) {
DIR first = isNext ? direction.first : direction.first.inverse();
DIR second = isNext ? direction.second : direction.second.inverse();
DIR horDir = first.isX() ? first : second;
DIR vertDir = first.isX() ? second : first;
boolean inverse = !direction.isLeftToRight();
horDir = inverse ? horDir.inverse() : horDir;
info.x.offset = reset(horDir, info.x, doCentering);
info.x.offset = inverse ? info.x.pageDimension - info.x.screenDimension - info.x.offset : info.x.offset;
info.y.offset = reset(vertDir, info.y, doCentering);
}
public String getDirection() {
return direction.name();
}
}