/* GanttProject is an opensource project management tool. License: GPL3 Copyright (C) 2010-2011 Dmitry Barashev, GanttProject Team 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package biz.ganttproject.core.chart.grid; import java.util.Date; import java.util.List; /** * Finds the bounds of the given date range in the given list of offsets. * * @author dbarashev (Dmitry Barashev) */ public class OffsetLookup { public static interface ComparatorBy<T> { int compare(T point, int offsetIdx, List<Offset> offsets); } static class ComparatorByStartDate implements ComparatorBy<Date> { @Override public int compare(Date point, int offsetIdx, List<Offset> offsets) { return point.compareTo(offsets.get(offsetIdx).getOffsetStart()); } } static class ComparatorByEndDate implements ComparatorBy<Date> { @Override public int compare(Date point, int offsetIdx, List<Offset> offsets) { return point.compareTo(offsets.get(offsetIdx).getOffsetEnd()); } } public static final ComparatorBy<Date> BY_START_DATE = new ComparatorByStartDate(); public static final ComparatorBy<Date> BY_END_DATE = new ComparatorByEndDate(); private <Type> int findOffset(Type point, ComparatorBy<Type> comparator, int start, int end, List<Offset> offsets) { if (comparator.compare(point, end, offsets) > 0) { return -end - 2; } if (comparator.compare(point, start, offsets) < 0) { return start; } for (int compare = comparator.compare(point, start, offsets); compare != 0; compare = comparator.compare(point, start, offsets)) { if (end == start) { start = -start - 1; break; } if (end < start) { throw new IllegalStateException("end=" + end + " start=" + start + " date=" + point + " offset=" + offsets.get(start)); } int diff = end - start; if (compare == 1) { start += diff == 1 ? 1 : diff / 2; } else { end = start; start -= diff == 1 ? 1 : diff / 2; } } return start; } public int[] getBounds(Date startDate, Date endDate, List<Offset> offsets) { int end = offsets.size() - 1; int start = 0; ComparatorByEndDate comparator = new ComparatorByEndDate(); if (startDate.compareTo(offsets.get(start).getOffsetEnd()) > 0) { start = findOffset(startDate, comparator, start, end, offsets); } if (start < 0) { start = -start - 1; } int leftX = start == offsets.size() ? offsets.get(start - 1).getOffsetPixels() : offsets.get(start).getOffsetPixels(); end = offsets.size() - 1; if (endDate.compareTo(offsets.get(end).getOffsetEnd()) < 0) { end = findOffset(endDate, comparator, 0, end, offsets); } if (end < 0) { end = -end - 1; } int rightX = end == offsets.size() ? offsets.get(end - 1).getOffsetPixels() : offsets.get(end).getOffsetPixels(); return new int[] { leftX, rightX }; } public int lookupOffsetBy(Date date, List<Offset> offsets, ComparatorBy<Date> comparator) { return findOffset(date, comparator, 0, offsets.size() - 1, offsets); } public int lookupOffsetByStartDate(Date startDate, List<Offset> offsets) { ComparatorByStartDate comparator = new ComparatorByStartDate(); return findOffset(startDate, comparator, 0, offsets.size() - 1, offsets); } public int lookupOffsetByEndDate(Date endDate, List<Offset> offsets) { ComparatorByEndDate comparator = new ComparatorByEndDate(); return findOffset(endDate, comparator, 0, offsets.size() - 1, offsets); } static class ComparatorByPixels implements ComparatorBy<Integer> { @Override public int compare(Integer point, int offsetIdx, List<Offset> offsets) { Offset offset = offsets.get(offsetIdx); if (offset.getOffsetPixels() > point) { return 1; } if (offsetIdx == offsets.size() - 1) { return 0; } Offset rightOffset = offsets.get(offsetIdx + 1); if (rightOffset.getOffsetPixels() > point) { return 0; } return -1; } } Date lookupDateByPixels(int pixels, List<Offset> offsets) { int offsetIdx = findOffset(pixels, new ComparatorByPixels(), 0, offsets.size() - 1, offsets); if (offsetIdx < 0) { offsetIdx = -offsetIdx - 1; } Offset offset = offsets.get(offsetIdx); return offset.getOffsetStart(); } }