3 import java.util.ArrayList;
\r
4 import java.util.Calendar;
\r
5 import java.util.GregorianCalendar;
\r
6 import java.util.HashMap;
\r
7 import java.util.regex.Matcher;
\r
8 import java.util.regex.Pattern;
\r
10 import tainavi.TVProgram.ProgOption;
\r
11 import tainavi.TVProgram.ProgType;
\r
14 * 検索は都度行うのではなく、番組表を読み込んだり検索条件を変更したりといったイベントの際に全件作成してしまって、表示はそれを絞り込むだけにして高速化をはかる
\r
16 public class MarkedProgramList {
\r
22 private static final String MSGID = "[検索結果生成] ";
\r
23 //private static final String ERRID = "[ERROR]"+MSGID;
\r
24 //private static final String DBGID = "[DEBUG]"+MSGID;
\r
30 private ArrayList<ProgDetailList> programs = null;
\r
31 private ArrayList<ArrayList<TraceKey>> traceKeys = null;
\r
32 private ArrayList<ArrayList<Integer>> traceScores = null;
\r
33 private ArrayList<ArrayList<SearchKey>> searchKeys = null;
\r
34 private ArrayList<ArrayList<String>> searchStrs = null;
\r
36 public ProgDetailList getProg(int n) { return this.programs.get(n); }
\r
37 public ArrayList<TraceKey> getTKey(int n) { return this.traceKeys.get(n); }
\r
38 public ArrayList<Integer> getTScore(int n) { return this.traceScores.get(n); }
\r
39 public ArrayList<SearchKey> getSKey(int n) { return this.searchKeys.get(n); }
\r
40 public ArrayList<String> getSStr(int n) { return this.searchStrs.get(n); }
\r
42 public int size() { return (programs==null)?(0):(programs.size()); }
\r
44 private boolean disableFazzySearch = false;
\r
45 private boolean disableFazzySearchReverse = false;
\r
48 private boolean historyOnlyUpdateOnce = false;
\r
49 public void setHistoryOnlyUpdateOnce(boolean b) { historyOnlyUpdateOnce = b; }
\r
52 private boolean showOnlyNonrepeated = true;
\r
53 public void setShowOnlyNonrepeated(boolean b) { showOnlyNonrepeated = b; }
\r
58 public void build(ArrayList<TVProgram> progs, ArrayList<TraceKey> trKeys, ArrayList<SearchKey> srKeys) {
\r
60 clearMarkedFlag(progs);
\r
63 for (TraceKey trace : trKeys) {
\r
64 buildByKeyword(progs, trace, null);
\r
67 for (SearchKey search : srKeys) {
\r
68 buildByKeyword(progs, null, search);
\r
75 * 検索条件がかわったなら全番組のフラグを初期化しないといけない
\r
77 private void clearMarkedFlag(ArrayList<TVProgram> tvprograms) {
\r
78 for ( TVProgram tvp : tvprograms ) {
\r
79 if (tvp.getType() != TVProgram.ProgType.PROG && tvp.getType() != TVProgram.ProgType.SYOBO) {
\r
83 for ( ProgList tvpl : tvp.getCenters() ) {
\r
84 if ( ! tvpl.enabled) {
\r
88 for ( ProgDateList tvc : tvpl.pdate ) {
\r
89 for ( ProgDetailList tvd : tvc.pdetail ) {
\r
91 tvd.nonrepeated = false;
\r
92 tvd.showinstandby = false;
\r
99 private void buildByKeyword(ArrayList<TVProgram> tvprograms, TraceKey tKey, SearchKey sKye) {
\r
100 // 検索条件のマッチカウントのクリア
\r
101 SearchItem item = tKey != null ? tKey : sKye;
\r
102 item.clearMatchedList();
\r
105 for (int siteid=0; siteid<tvprograms.size(); siteid++) {
\r
107 TVProgram tvp = tvprograms.get(siteid);
\r
109 if (tvp.getType() != TVProgram.ProgType.PROG && tvp.getType() != TVProgram.ProgType.SYOBO) {
\r
113 for (int centerid=0; centerid<tvp.getCenters().size(); centerid++) {
\r
115 ProgList tvpl = tvp.getCenters().get(centerid);
\r
117 if ( ! tvpl.enabled) {
\r
121 if (tKey != null && ! tKey.getCenter().equals(tvpl.Center) ) {
\r
125 if ( tKey != null && tKey.getShowLatestOnly() ) {
\r
126 System.out.println(MSGID+"[リピート放送判定] リピート放送を排除する検索キー: *"+tvp.getType()+"* "+tKey._getLabel());
\r
130 MatchedBuffer mBuf = new MatchedBuffer();
\r
133 String centerPop = TraceProgram.replacePop(tvpl.Center);
\r
135 for (int dateid=0; dateid<tvpl.pdate.size(); dateid++) {
\r
136 String matchedString = null;
\r
137 ProgDateList tvc = tvpl.pdate.get(dateid);
\r
138 for (int progid=0; progid<tvc.pdetail.size(); progid++) {
\r
139 ProgDetailList tvd = tvc.pdetail.get(progid);
\r
141 // 番組情報がありませんは表示しない
\r
142 if (tvd.start.equals("")) {
\r
148 boolean isFind = false;
\r
149 if (tKey != null) {
\r
150 if (tKey.getDisableRepeat() == true && tvd.isOptionEnabled(ProgOption.REPEAT)) {
\r
155 if (this.disableFazzySearch == true) {
\r
157 if (tKey._getTitlePop().equals(tvd.titlePop)) {
\r
163 String target = ProgDetailList.tracenOnlyTitle ? tvd.splitted_titlePop : tvd.titlePop;
\r
164 fazScore = TraceProgram.sumScore(target, tKey._getTitlePop());
\r
165 if (fazScore >= tKey.getFazzyThreshold()) {
\r
168 else if ( ! this.disableFazzySearchReverse) {
\r
170 fazScore = TraceProgram.sumScore(tKey._getTitlePop(), target);
\r
171 if (fazScore >= tKey.getFazzyThreshold()) {
\r
177 else if (sKye != null) {
\r
178 isFind = SearchProgram.isMatchKeyword(sKye, ((sKye.getCaseSensitive()==false)?(centerPop):(tvpl.Center)), tvd);
\r
180 matchedString = SearchProgram.getMatchedString();
\r
186 mBuf.add(tvd, tKey, fazScore, sKye, matchedString);
\r
190 for ( MatchedBufferData d : mBuf.getData() ) {
\r
191 if ( d.prog.marked ) {
\r
192 if ( tKey != null && tKey.getShowLatestOnly() ) {
\r
193 System.out.println(MSGID+"[リピート放送判定] [結果] リピート放送ではないと判断されました: "+d.prog.startDateTime+" 「"+d.prog.title+"("+d.bareTitle+")」 ("+d.storyNo+")");
\r
194 d.prog.nonrepeated = true;
\r
196 if ( ! (sKye != null && ! sKye.getShowInStandby()) ) {
\r
197 d.prog.showinstandby = true;
\r
199 this.add(d.prog, d.tKey, d.tScore, d.sKey, d.sStr);
\r
202 if ( tKey != null && tKey.getShowLatestOnly() ) {
\r
203 if ( ! showOnlyNonrepeated ) {
\r
205 d.prog.marked = true;
\r
206 if ( sKye != null && sKye.getShowInStandby() ) {
\r
207 d.prog.showinstandby = true;
\r
209 this.add(d.prog, d.tKey, d.tScore, d.sKey, d.sStr);
\r
219 private class MatchedBufferData {
\r
220 public ProgDetailList prog = null;
\r
221 public TraceKey tKey = null;
\r
222 public int tScore = 0;
\r
223 public SearchKey sKey = null;
\r
224 public String sStr = null;
\r
226 public String bareTitle = null;
\r
227 public Integer storyNo = null;
\r
229 public MatchedBufferData(ProgDetailList prog, TraceKey tKey, int tScore, SearchKey sKey, String sStr) {
\r
232 this.tScore = tScore;
\r
236 this.bareTitle = null;
\r
237 this.storyNo = null;
\r
240 private class MatchedBuffer {
\r
242 public ArrayList<MatchedBufferData> data = new ArrayList<MatchedBufferData>();
\r
243 public String xDateTime = null ;
\r
246 public MatchedBuffer() {
\r
247 GregorianCalendar c = CommonUtils.getCalendar(0);
\r
248 if ( CommonUtils.isLateNight(c) ) {
\r
249 c.add(Calendar.DATE, 6);
\r
252 c.add(Calendar.DATE, 7);
\r
254 c.set(Calendar.HOUR_OF_DAY, 5);
\r
255 c.set(Calendar.MINUTE, 0);
\r
256 xDateTime = CommonUtils.getDateTime(c);
\r
260 public ArrayList<MatchedBufferData> getData() {
\r
264 private final String[] exprs = {
\r
267 "第([0-90-9]+)[話回]",
\r
269 "[((]([0-90-9]+?)[))]",
\r
273 public void add(ProgDetailList prog, TraceKey tKey, int tScore, SearchKey sKey, String sStr) {
\r
274 MatchedBufferData bd = new MatchedBufferData(prog, tKey, tScore, sKey, sStr);
\r
275 if ( tKey == null || ! tKey.getShowLatestOnly() ) {
\r
276 // キーワード検索だったりリピート有効な場合はそのまま
\r
282 // タイトルと番組詳細両方でしらべるもの
\r
283 for ( String expr : exprs ) {
\r
284 Matcher ma = Pattern.compile(expr).matcher(prog.title);
\r
286 bd.storyNo = Integer.valueOf(CommonUtils.toHANUM(ma.group(1)));
\r
289 ma = Pattern.compile("^[ \t]*"+expr).matcher(prog.detail);
\r
291 bd.storyNo = Integer.valueOf(CommonUtils.toHANUM(ma.group(1)));
\r
296 if ( bd.storyNo != null ) {
\r
299 //bd.storyNo = CommonUtils.toHANUM(bd.storyNo);
\r
301 // 同一タイトルで重複するものを排除する
\r
303 // 話数を外した裸のタイトルだけを抽出する
\r
304 bd.bareTitle = TraceProgram.replacePop(prog.title.replaceFirst("\\s*([##][0-90-9]+|[((][0-90-9]+[))]|第[0-90-9]+[話回]).*$", ""));
\r
306 for ( MatchedBufferData d : data ) {
\r
307 if ( d.prog.marked == false ) {
\r
311 if ( prog.startDateTime.compareTo(xDateTime) < 0) {
\r
313 if ( d.bareTitle != null && d.bareTitle.equals(bd.bareTitle) ) {
\r
314 if ( d.storyNo != null && d.storyNo >= bd.storyNo ) {
\r
315 // 同じかより新しいものがすでにあったら自分を捨てる
\r
316 bd.prog.marked = false;
\r
317 System.out.println(MSGID+"[リピート放送判定] [結果] リピート放送と判定されました(すでに新しいものがある): "+bd.prog.startDateTime+" 「"+bd.prog.title+"("+bd.bareTitle+")」 ("+bd.storyNo+")");
\r
321 d.prog.marked = false;
\r
322 System.out.println(MSGID+"[リピート放送判定] [結果] リピート放送と判定されました(より新し番組がみつかった): "+d.prog.startDateTime+" 「"+d.prog.title+"("+d.bareTitle+")」 ("+d.storyNo+")");
\r
328 if ( d.bareTitle != null && d.bareTitle.equals(bd.bareTitle) ) {
\r
329 if ( d.storyNo != null && d.storyNo >= bd.storyNo ) {
\r
330 // 同じかより新しいものがすでにあったら自分を捨てる
\r
331 bd.prog.marked = false;
\r
332 System.out.println(MSGID+"[リピート放送判定] [結果] リピート放送と判定されました(すでに新しいものがある[8日目]): "+bd.prog.startDateTime+" 「"+bd.prog.title+"("+bd.bareTitle+")」 ("+bd.storyNo+")");
\r
335 // 自分より古いものがあってもなにもしない
\r
343 bd.bareTitle = TraceProgram.replacePop(prog.title);
\r
350 private void add(ProgDetailList prog, TraceKey tKey, int tScore, SearchKey sKey, String sStr) {
\r
352 // 検索条件のマッチカントをカウントアップ
\r
353 SearchItem item = sKey != null ? sKey : tKey;
\r
354 if (item != null && prog.type == ProgType.PROG) {
\r
355 item.addMatchedList(prog);
\r
360 for (int n=0; n<this.programs.size(); n++) {
\r
361 if (this.programs.get(n).equals(prog)) {
\r
362 if (tKey != null) {
\r
363 this.traceKeys.get(n).add(tKey);
\r
364 this.traceScores.get(n).add(tScore);
\r
366 else if (sKey != null) {
\r
367 this.searchKeys.get(n).add(sKey);
\r
368 this.searchStrs.get(n).add(sStr);
\r
378 for (; p<this.programs.size(); p++) {
\r
379 if (this.programs.get(p).startDateTime.compareTo(prog.startDateTime) > 0) {
\r
384 this.programs.add(p,prog);
\r
385 this.traceKeys.add(p, new ArrayList<TraceKey>());
\r
386 this.traceScores.add(p, new ArrayList<Integer>());
\r
387 this.searchKeys.add(p, new ArrayList<SearchKey>());
\r
388 this.searchStrs.add(p, new ArrayList<String>());
\r
389 if (tKey != null) {
\r
390 this.traceKeys.get(p).add(tKey);
\r
391 this.traceScores.get(p).add(tScore);
\r
393 if (sKey != null) {
\r
394 this.searchKeys.get(p).add(sKey);
\r
395 this.searchStrs.get(p).add(sStr);
\r
400 public void clear(boolean b1, boolean b2) {
\r
402 this.disableFazzySearch = b1;
\r
403 this.disableFazzySearchReverse = b2;
\r
406 this.programs = new ArrayList<ProgDetailList>();
\r
408 this.traceKeys = new ArrayList<ArrayList<TraceKey>>();
\r
409 this.traceKeys.add(new ArrayList<TraceKey>());
\r
410 this.traceScores = new ArrayList<ArrayList<Integer>>();
\r
411 this.traceScores.add(new ArrayList<Integer>());
\r
413 this.searchKeys = new ArrayList<ArrayList<SearchKey>>();
\r
414 this.searchKeys.add(new ArrayList<SearchKey>());
\r
415 this.searchStrs = new ArrayList<ArrayList<String>>();
\r
416 this.searchStrs.add(new ArrayList<String>());
\r
419 // 検索結果の履歴と突き合わせて新着をチェックする
\r
420 public void chkNewArrival() {
\r
422 MarkedHistoryList oldhist = MarkedHistoryList.load(historyOnlyUpdateOnce);
\r
423 MarkedHistoryList newhist = new MarkedHistoryList();
\r
425 int max = this.size();
\r
426 for ( int i=0; i<max; i++ ) {
\r
428 // 通常の番組情報のみ(しょぼかるは対象外)
\r
429 if ( this.getProg(i).type != ProgType.PROG ) {
\r
433 MarkedHistory mh = new MarkedHistory();
\r
434 mh.setCenter(this.getProg(i).center);
\r
435 mh.setStartDateTime(this.getProg(i).startDateTime);
\r
436 mh.setDetail(this.getProg(i).detail);
\r
438 // 番組追跡とキーワード検索のダブリを排除
\r
439 if ( newhist.isMatch(mh) ) {
\r
443 // 新着チェック( ! isMatch()注意)
\r
444 this.getProg(i).newarrival = ! oldhist.isMatch(mh);
\r
445 this.getProg(i).modified = (this.getProg(i).newarrival)?(false):(oldhist.isModified(mh));
\r
452 newhist.save(historyOnlyUpdateOnce);
\r