import java.io.*; class Profile { static final int MIN_INTERVAL = 21; static final int MAX_INTERVAL = 39; static final int MAX_SIZE = 255; private static final int VERSION_1 = 1, VERSION_2 = 2; int size = 2; short dates[] = new short[MAX_SIZE]; int colorScheme = 0; int periodLen = 5; int lutealLen = 14; int goal = 0; String name = ""; Profile(String iniName) { name = iniName; dates[0] = 0; dates[1] = Short.MAX_VALUE; } Profile(DataInput in, int version) throws IOException { if (version >= VERSION_2) { name = in.readUTF(); colorScheme = in.readShort(); periodLen = in.readShort(); lutealLen = in.readShort(); goal = in.readShort(); size = in.readShort(); for (int i = 0; i < size; ++i) { dates[i] = in.readShort(); } } else { //version 1 int settings = in.readShort(); in.readShort(); //passwd, ignored size = in.readShort(); for (int i = 0; i < size; ++i) { dates[i] = in.readShort(); } name = ""; colorScheme = settings & 0x000f; periodLen = (settings & 0x00f0) >> 4; lutealLen = ((settings & 0x0f00) >> 8) + 4; goal = (settings & 0x3000) >> 12; } } void writeTo(DataOutput out) throws IOException { out.writeUTF(name); out.writeShort(colorScheme); out.writeShort(periodLen); out.writeShort(lutealLen); out.writeShort(goal); out.writeShort(size); for (int i = 0; i < size; ++i) { out.writeShort(dates[i]); } } String[] periodList() { int year, month, day, len; String lines[] = new String[size-2]; int[] ymd = new int[3]; for (int i = 1; i < size - 1; ++i) { Cal.toYMD(dates[i], ymd); year = ymd[0]; month = ymd[1] + 1; day = ymd[2]; len = 200; len = dates[i+1] - dates[i]; lines[i-1] = "" + year + '-' + month + '-' + day + " " + ((len<100) ? (""+len) : "--"); } return lines; } private static final String SMS_HEADER = "Menstral\n"; String serializeDates() { StringBuffer str = new StringBuffer(); str.setLength(0); str.append(SMS_HEADER); int curYear = 0; int curMonth = 0; int year, month, day; int[] ymd = new int[3]; for (int i = 1; i < size - 1; ++i) { Cal.toYMD(dates[i], ymd); year = ymd[0]; month = ymd[1] + 1; day = ymd[2]; if (year != curYear) { str.append('\n').append(year).append(':'); curYear = year; curMonth = 1; } str.append(' ').append(day); if (month != curMonth) { str.append('/').append(month); curMonth = month; } ++curMonth; } return str.toString(); } int findPos(short date) { int pos = 0; while (pos < size && dates[pos] <= date) { ++pos; } //assrt(pos < size); --pos; return pos; } void toggle(short date) { int pos = findPos(date); if (dates[pos] == date) { remove(date); } else { add(date); } } private void add(short date) { if (size == MAX_SIZE) { return; //full, can't add } int pos = findPos(date); if (dates[pos] != date) { ++pos; ++size; for (int i = size; i > pos; --i) { dates[i] = dates[i - 1]; } dates[pos] = date; } } private void remove(short date) { int pos = findPos(date); if (dates[pos] == date) { --size; for (int i = pos; i < size; ++i) { dates[i] = dates[i + 1]; } } } boolean isMarked(short d) { return dates[findPos(d)] == d; } public int getDaysInfo(short date, Region outRegs[]) { int nRegs = 0; short endDate = (short)(date + DateCanvas.N_DAYS_1); int firstDay = 0; int ret; Region r; r = outRegs[nRegs++]; ret = doRegion(date, r); firstDay = ret + 1; //assrt(r.avg > 0); date += r.len + ret; while (date < endDate && nRegs < DateCanvas.N_REGS) { r = outRegs[nRegs++]; ret = doRegion(date, r); //assrt(ret == 0 && r.avg > 0); date += r.len; //System.out.println(r); } return firstDay; } static void computeFitInterval(int avg, int date1, int date2, int date, int out[]) { int len = date2 - date1; int fitLen = computeFitLen(avg, len); //assrt(date1 <= date && date <= date2); int dist = date - date1; int i = 1; while((i * fitLen + 49) / 100 <= dist) ++i; --i; int n = len * 100 / fitLen; int p1 = (i * fitLen + 49) / 100; int p2 = ((i + 1) * fitLen + 49) / 100; out[0] = i; out[1] = n; out[2] = date1 + p1; out[3] = p2 - p1; } static int computeFitLen(int avg, int len) { len *= 100; avg *= 100; int n = len / avg; if (n == 0) { return len; } int s1 = len / n; int s2 = len / (n + 1); return (s1 - avg < avg - s2) ? s1 : s2; } int intervals1[] = new int[13], intervals2[] = new int[13]; int doBefore(int intervals[], int pos) { int intSize = 0; int len; for (int i = pos; i > 0 && intSize < 10; --i, ++intSize) { len = dates[i] - dates[i - 1]; if (len < MIN_INTERVAL || len > MAX_INTERVAL) { break; } intervals[intSize] = len; } return intSize; } int doAfter(int intervals[], int pos) { int intSize = 0; int len; for (int i = pos + 1; i < size - 1 && intSize < 10; ++i, ++intSize) { len = dates[i + 1] - dates[i]; if (len < MIN_INTERVAL || len > MAX_INTERVAL) { break; } intervals[intSize] = len; } return intSize; } void computeAvgMinMax(int n, int[] values, int[] avgMinMax) { if (n > 0) { int min = values[0]; int max = min, sum = min; for (int i = 1; i < n; ++i) { int v = values[i]; sum += v; if (v < min) { min = v; } else if (v > max) { max = v; } } avgMinMax[0] = (sum + (n-1)/2) / n; avgMinMax[1] = min; avgMinMax[2] = max; } } int getAvgMinMax(int avgMinMax[]) { int n = doBefore(intervals1, size - 2); computeAvgMinMax(n, intervals1, avgMinMax); return n; } int computeExpectedLen(int size, int intervals[]) { if (size == 0) { return 28; } if (size > 7) { size = 7; } int[] avgMinMax = new int[3]; computeAvgMinMax(size, intervals, avgMinMax); return avgMinMax[0]; } int doRegion(short date, Region outReg) { int pos = findPos(date); boolean hasBefore = (pos > 0), hasAfter = (pos < size -2); //System.out.println("begin " + beginDay + // " pos " + pos + " b " + hasBefore + "; " + hasAfter); if (!hasBefore && !hasAfter) { outReg.setNoInfo(DateCanvas.N_DAYS); return 0; } int size1 = 0, size2 = 0; if (hasBefore) { size1 = doBefore(intervals1, pos); } if (hasAfter) { size2 = doAfter(intervals2, pos); } int beg, distN; int intervals[] = null; int intSize; if (size1 <= size2) { intervals = intervals2; intSize = size2; } else { intervals = intervals1; intSize = size1; } int avg = computeExpectedLen(intSize, intervals); if (hasBefore && hasAfter) { int out[] = new int[4]; computeFitInterval(avg, dates[pos], dates[pos + 1], date, out); int n1 = out[0], n = out[1], len = out[3]; beg = out[2]; distN = (n1 <= (n - n1 - 1)) ? n1 : (n - n1 -1); if (len < MIN_INTERVAL || len > MAX_INTERVAL) { outReg.setNoInfo(len); } else if (n == 1) { outReg.setExact(len); } else { outReg.set(len, intSize, intervals); } } else { if (hasBefore) { int dist = date - dates[pos]; //distN = dist / avg; beg = date - dist % avg; } else { int dist = dates[pos + 1] - date -1; //distN = dist / avg; beg = date - (avg - dist%avg - 1); } outReg.set(avg, intSize, intervals); } return beg - date; } }