/**************************************************************************
 *
 * QueryTester.cpp -- 
 * Copyright (C) 1999  Rodger McNab
 *
 * 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **************************************************************************/

#include "MGQuery.h"


class SetQueryNode : public QueryNode {
public:
  QueryResult queryResult;
  
  SetQueryNode () {}
  ~SetQueryNode () {}

  void Calculate (IndexData &/*indexData*/, const QueryInfo &queryInfo,
		  QueryResult &result) const {
    result = queryResult;
    if (!queryInfo.sortByRank && !queryInfo.needRankInfo)
      result.ranks.erase (result.ranks.begin(), result.ranks.end());
    if (!queryInfo.needTermFreqs)
      result.termFreqs.erase (result.termFreqs.begin(),
			      result.termFreqs.end());
  }
  void Free () { queryResult.Clear(); }
};


bool Test1 () {
  AndQueryNode andNode;

  SetQueryNode *setNode1 = new SetQueryNode;
  DocNumArray &docSet1 = setNode1->queryResult.docs;
  RankArray &rankSet1 = setNode1->queryResult.ranks;
  docSet1.push_back (1);  rankSet1.push_back (0.1f);
  docSet1.push_back (10); rankSet1.push_back (0.2f);
  docSet1.push_back (15); rankSet1.push_back (0.2f);
  docSet1.push_back (18); rankSet1.push_back (0.4f);
  docSet1.push_back (19); rankSet1.push_back (0.5f);

  SetQueryNode *setNode2 = new SetQueryNode;
  DocNumArray &docSet2 = setNode2->queryResult.docs;
  RankArray &rankSet2 = setNode2->queryResult.ranks;
  docSet2.push_back (2);  rankSet2.push_back (0.1f);
  docSet2.push_back (11); rankSet2.push_back (0.2f);
  docSet2.push_back (12); rankSet2.push_back (0.3f);
  docSet2.push_back (13); rankSet2.push_back (0.4f);
  docSet2.push_back (14); rankSet2.push_back (0.5f);
  docSet2.push_back (15); rankSet2.push_back (0.6f);
  docSet2.push_back (16); rankSet2.push_back (0.7f);
  docSet2.push_back (17); rankSet2.push_back (0.8f);
  docSet2.push_back (19); rankSet2.push_back (0.9f);
  docSet2.push_back (20); rankSet2.push_back (0.1f);
  docSet2.push_back (21); rankSet2.push_back (0.2f);

  cout << "\n" << setNode1->queryResult << "AND\n\n"
       << setNode2->queryResult;
  

  andNode.leftNode = setNode1;
  andNode.rightNode = setNode2;

  IndexData indexData; // this will not be used anywhere
  QueryInfo queryInfo;
  queryInfo.maxDocs = 0;
  queryInfo.sortByRank = true;
  queryInfo.needRankInfo = true;
  queryInfo.needTermFreqs = true;
  
  QueryResult result;

  andNode.Calculate(indexData, queryInfo, result);

  cout << "EQUALS\n\n" << result << "\n";

  QueryResult resultCompare;
  DocNumArray &rcDocSet = resultCompare.docs;
  RankArray &rcRankSet = resultCompare.ranks;
  rcDocSet.push_back (15);  rcRankSet.push_back (0.2+0.6);
  rcDocSet.push_back (19);  rcRankSet.push_back (1.4);

  if (!(result == resultCompare)) {
    cout << "Test failed!!!\n";
    cout << resultCompare;
    return false;
  }

  return true;
}

bool Test1b () {
  AndQueryNode andNode;

  SetQueryNode *setNode1 = new SetQueryNode;
  DocNumArray &docSet1 = setNode1->queryResult.docs;
  docSet1.push_back (1); 
  docSet1.push_back (10);
  docSet1.push_back (15);
  docSet1.push_back (18);
  docSet1.push_back (19);

  SetQueryNode *setNode2 = new SetQueryNode;
  DocNumArray &docSet2 = setNode2->queryResult.docs;
  docSet2.push_back (2); 
  docSet2.push_back (11);
  docSet2.push_back (12);
  docSet2.push_back (13);
  docSet2.push_back (14);
  docSet2.push_back (15);
  docSet2.push_back (16);
  docSet2.push_back (17);
  docSet2.push_back (19);
  docSet2.push_back (20);
  docSet2.push_back (21);

  cout << "\n" << setNode1->queryResult << "AND\n\n"
       << setNode2->queryResult;
  

  andNode.leftNode = setNode1;
  andNode.rightNode = setNode2;

  IndexData indexData; // this will not be used anywhere
  QueryInfo queryInfo;
  queryInfo.maxDocs = 0;
  queryInfo.sortByRank = false;
  queryInfo.needRankInfo = false;
  queryInfo.needTermFreqs = true;
  
  QueryResult result;

  andNode.Calculate(indexData, queryInfo, result);

  cout << "EQUALS\n\n" << result << "\n";

  QueryResult resultCompare;
  DocNumArray &rcDocSet = resultCompare.docs;
  rcDocSet.push_back (15); 
  rcDocSet.push_back (19); 

  if (!(result == resultCompare)) {
    cout << "Test failed!!!\n";
    cout << resultCompare;
    return false;
  }

  return true;
}

bool Test2 () {
  OrQueryNode orNode;

  SetQueryNode *setNode1 = new SetQueryNode;
  DocNumArray &docSet1 = setNode1->queryResult.docs;
  RankArray &rankSet1 = setNode1->queryResult.ranks;
  docSet1.push_back (1);  rankSet1.push_back (0.1f);
  docSet1.push_back (10); rankSet1.push_back (0.2f);
  docSet1.push_back (15); rankSet1.push_back (0.2f);
  docSet1.push_back (18); rankSet1.push_back (0.4f);
  docSet1.push_back (19); rankSet1.push_back (0.5f);

  SetQueryNode *setNode2 = new SetQueryNode;
  DocNumArray &docSet2 = setNode2->queryResult.docs;
  RankArray &rankSet2 = setNode2->queryResult.ranks;
  docSet2.push_back (2);  rankSet2.push_back (0.1f);
  docSet2.push_back (11); rankSet2.push_back (0.2f);
  docSet2.push_back (12); rankSet2.push_back (0.3f);
  docSet2.push_back (13); rankSet2.push_back (0.4f);
  docSet2.push_back (14); rankSet2.push_back (0.5f);
  docSet2.push_back (15); rankSet2.push_back (0.6f);
  docSet2.push_back (16); rankSet2.push_back (0.7f);
  docSet2.push_back (17); rankSet2.push_back (0.8f);
  docSet2.push_back (19); rankSet2.push_back (0.9f);
  docSet2.push_back (20); rankSet2.push_back (0.1f);
  docSet2.push_back (21); rankSet2.push_back (0.2f);

  cout << "\n" << setNode1->queryResult << "OR\n\n"
       << setNode2->queryResult;
  

  orNode.leftNode = setNode1;
  orNode.rightNode = setNode2;

  IndexData indexData; // this will not be used anywhere
  QueryInfo queryInfo;
  queryInfo.maxDocs = 0;
  queryInfo.sortByRank = true;
  queryInfo.needRankInfo = true;
  queryInfo.needTermFreqs = true;
  
  QueryResult result;

  orNode.Calculate(indexData, queryInfo, result);

  cout << "EQUALS\n\n" << result << "\n";

  QueryResult resultCompare;
  DocNumArray &rcDocSet = resultCompare.docs;
  RankArray &rcRankSet = resultCompare.ranks;
  rcDocSet.push_back (1);  rcRankSet.push_back (0.1f);
  rcDocSet.push_back (2);  rcRankSet.push_back (0.1f);
  rcDocSet.push_back (10); rcRankSet.push_back (0.2f);
  rcDocSet.push_back (11); rcRankSet.push_back (0.2f);
  rcDocSet.push_back (12); rcRankSet.push_back (0.3f);
  rcDocSet.push_back (13); rcRankSet.push_back (0.4f);
  rcDocSet.push_back (14); rcRankSet.push_back (0.5f);
  rcDocSet.push_back (15); rcRankSet.push_back (0.2f+0.6f);
  rcDocSet.push_back (16); rcRankSet.push_back (0.7f);
  rcDocSet.push_back (17); rcRankSet.push_back (0.8f);
  rcDocSet.push_back (18); rcRankSet.push_back (0.4f);
  rcDocSet.push_back (19); rcRankSet.push_back (0.9f+0.5f);
  rcDocSet.push_back (20); rcRankSet.push_back (0.1f);
  rcDocSet.push_back (21); rcRankSet.push_back (0.2f);
  

  if (!(result == resultCompare)) {
    cout << "Test failed!!!\n";
    cout << resultCompare;
    return false;
  }

  return true;
}

bool Test2b () {
  OrQueryNode orNode;

  SetQueryNode *setNode1 = new SetQueryNode;
  DocNumArray &docSet1 = setNode1->queryResult.docs;
  docSet1.push_back (1); 
  docSet1.push_back (10);
  docSet1.push_back (15);
  docSet1.push_back (18);
  docSet1.push_back (19);

  SetQueryNode *setNode2 = new SetQueryNode;
  DocNumArray &docSet2 = setNode2->queryResult.docs;
  docSet2.push_back (2);
  docSet2.push_back (11);
  docSet2.push_back (12);
  docSet2.push_back (13);
  docSet2.push_back (14);
  docSet2.push_back (15);
  docSet2.push_back (16);
  docSet2.push_back (17);
  docSet2.push_back (19);
  docSet2.push_back (20);
  docSet2.push_back (21);

  cout << "\n" << setNode1->queryResult << "OR\n\n"
       << setNode2->queryResult;
  

  orNode.leftNode = setNode1;
  orNode.rightNode = setNode2;

  IndexData indexData; // this will not be used anywhere
  QueryInfo queryInfo;
  queryInfo.maxDocs = 0;
  queryInfo.sortByRank = false;
  queryInfo.needRankInfo = false;
  queryInfo.needTermFreqs = true;
  
  QueryResult result;

  orNode.Calculate(indexData, queryInfo, result);

  cout << "EQUALS\n\n" << result << "\n";

  QueryResult resultCompare;
  DocNumArray &rcDocSet = resultCompare.docs;
  rcDocSet.push_back (1);
  rcDocSet.push_back (2); 
  rcDocSet.push_back (10);
  rcDocSet.push_back (11);
  rcDocSet.push_back (12);
  rcDocSet.push_back (13);
  rcDocSet.push_back (14);
  rcDocSet.push_back (15);
  rcDocSet.push_back (16);
  rcDocSet.push_back (17);
  rcDocSet.push_back (18);
  rcDocSet.push_back (19);
  rcDocSet.push_back (20);
  rcDocSet.push_back (21);
  

  if (!(result == resultCompare)) {
    cout << "Test failed!!!\n";
    cout << resultCompare;
    return false;
  }

  return true;
}

bool Test3 () {
  NotQueryNode notNode;

  SetQueryNode *setNode1 = new SetQueryNode;
  DocNumArray &docSet1 = setNode1->queryResult.docs;
  RankArray &rankSet1 = setNode1->queryResult.ranks;
  docSet1.push_back (1);  rankSet1.push_back (0.1f);
  docSet1.push_back (10); rankSet1.push_back (0.2f);
  docSet1.push_back (15); rankSet1.push_back (0.2f);
  docSet1.push_back (18); rankSet1.push_back (0.4f);
  docSet1.push_back (19); rankSet1.push_back (0.5f);

  SetQueryNode *setNode2 = new SetQueryNode;
  DocNumArray &docSet2 = setNode2->queryResult.docs;
  RankArray &rankSet2 = setNode2->queryResult.ranks;
  docSet2.push_back (2);  rankSet2.push_back (0.1f);
  docSet2.push_back (11); rankSet2.push_back (0.2f);
  docSet2.push_back (12); rankSet2.push_back (0.3f);
  docSet2.push_back (13); rankSet2.push_back (0.4f);
  docSet2.push_back (14); rankSet2.push_back (0.5f);
  docSet2.push_back (15); rankSet2.push_back (0.6f);
  docSet2.push_back (16); rankSet2.push_back (0.7f);
  docSet2.push_back (17); rankSet2.push_back (0.8f);
  docSet2.push_back (19); rankSet2.push_back (0.9f);
  docSet2.push_back (20); rankSet2.push_back (0.1f);
  docSet2.push_back (21); rankSet2.push_back (0.2f);

  cout << "\n" << setNode1->queryResult << "NOT\n\n"
       << setNode2->queryResult;
  

  notNode.queryNode = setNode1;
  notNode.notNode = setNode2;

  IndexData indexData; // this will not be used anywhere
  QueryInfo queryInfo;
  queryInfo.maxDocs = 0;
  queryInfo.sortByRank = true;
  queryInfo.needRankInfo = true;
  queryInfo.needTermFreqs = true;
  
  QueryResult result;

  notNode.Calculate(indexData, queryInfo, result);

  cout << "EQUALS\n\n" << result << "\n";

  QueryResult resultCompare;
  DocNumArray &rcDocSet = resultCompare.docs;
  RankArray &rcRankSet = resultCompare.ranks;
  rcDocSet.push_back (1);  rcRankSet.push_back (0.1);
  rcDocSet.push_back (10); rcRankSet.push_back (0.2);
  rcDocSet.push_back (18); rcRankSet.push_back (0.4);
  

  if (!(result == resultCompare)) {
    cout << "Test failed!!!\n";
    cout << resultCompare;
    return false;
  }

  return true;
}

bool Test3b () {
  NotQueryNode notNode;

  SetQueryNode *setNode1 = new SetQueryNode;
  DocNumArray &docSet1 = setNode1->queryResult.docs;
  docSet1.push_back (1); 
  docSet1.push_back (10);
  docSet1.push_back (15);
  docSet1.push_back (18);
  docSet1.push_back (19);

  SetQueryNode *setNode2 = new SetQueryNode;
  DocNumArray &docSet2 = setNode2->queryResult.docs;
  docSet2.push_back (2); 
  docSet2.push_back (11);
  docSet2.push_back (12);
  docSet2.push_back (13);
  docSet2.push_back (14);
  docSet2.push_back (15);
  docSet2.push_back (16);
  docSet2.push_back (17);
  docSet2.push_back (19);
  docSet2.push_back (20);
  docSet2.push_back (21);

  cout << "\n" << setNode1->queryResult << "NOT\n\n"
       << setNode2->queryResult;
  

  notNode.queryNode = setNode1;
  notNode.notNode = setNode2;

  IndexData indexData; // this will not be used anywhere
  QueryInfo queryInfo;
  queryInfo.maxDocs = 0;
  queryInfo.sortByRank = false;
  queryInfo.needRankInfo = false;
  queryInfo.needTermFreqs = true;
  
  QueryResult result;

  notNode.Calculate(indexData, queryInfo, result);

  cout << "EQUALS\n\n" << result << "\n";

  QueryResult resultCompare;
  DocNumArray &rcDocSet = resultCompare.docs;
  rcDocSet.push_back (1); 
  rcDocSet.push_back (10);
  rcDocSet.push_back (18);
  

  if (!(result == resultCompare)) {
    cout << "Test failed!!!\n";
    cout << resultCompare;
    return false;
  }

  return true;
}


int main () {
  if (!Test1 () ||
      !Test2 () ||
      !Test2b () ||
      !Test3 () ||
      !Test3b ()) return 1;
  
  return 0;
}
