/* -*- C++ -*-
 *
 * This file is a part of LEMON, a generic C++ optimization library
 *
 * Copyright (C) 2003-2006
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
 *
 * Permission to use, modify and distribute this software is granted
 * provided that this copyright notice appears in all copies. For
 * precise terms see the accompanying LICENSE file.
 *
 * This software is provided "AS IS" with no warranty of any kind,
 * express or implied, and with no claim as to its suitability for any
 * purpose.
 *
 */

#include <iostream>
#include <vector>

#include <lemon/concept_check.h>

#include <lemon/concept/matrix_maps.h>
#include <lemon/concept/maps.h>
#include <lemon/concept/graph.h>

#include <lemon/matrix_maps.h>

#include <lemon/smart_graph.h>

#include "test_tools.h"
#include "graph_test.h"
#include "map_test.h"


using namespace lemon;
using namespace lemon::concept;

int main() {
  typedef SmartGraph Graph;
  typedef Graph::Node Node;
  typedef Graph::Edge Edge;

  { // checking MatrixMap for int
    typedef DynamicMatrixMap<Graph, Node, int> IntMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Node, int, 
      IntMatrixMap::Reference, IntMatrixMap::ConstReference>,
      IntMatrixMap>();

  }

  { // checking MatrixMap for bool
    typedef DynamicMatrixMap<Graph, Node, bool> BoolMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Node, bool, 
      BoolMatrixMap::Reference, BoolMatrixMap::ConstReference>,
      BoolMatrixMap>();

  }

  {
    Graph graph;
    typedef DynamicMatrixMap<Graph, Node, int> IntMatrixMap;
    IntMatrixMap matrix(graph);
    for (int i = 0; i < 10; ++i) {
      graph.addNode();
    }
    for (Graph::NodeIt it(graph); it != INVALID; ++it) {
      for (Graph::NodeIt jt(graph); jt != INVALID; ++jt) {
	int val = urandom(100);
	matrix.set(it, jt, val);
	check(matrix(it, jt) == val, "Wrong assign");
	check(matrix(it, jt) == matrixRowMap(matrix, it)[jt], "Wrong rowMap");
	check(matrix(it, jt) == matrixColMap(matrix, jt)[it], "Wrong colMap");
      }
    }
    const IntMatrixMap& cm = matrix;
    for (Graph::NodeIt it(graph); it != INVALID; ++it) {
      for (Graph::NodeIt jt(graph); jt != INVALID; ++jt) {
	check(cm(it, jt) == matrixRowMap(cm, it)[jt], "Wrong rowMap");
	check(cm(it, jt) == matrixColMap(cm, jt)[it], "Wrong colMap");
      }
    }
  }

  { // checking MatrixMap for int
    typedef DynamicSymMatrixMap<Graph, Node, int> IntMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Node, int, 
      IntMatrixMap::Reference, IntMatrixMap::ConstReference>,
      IntMatrixMap>();

  }

  { // checking MatrixMap for bool
    typedef DynamicSymMatrixMap<Graph, Node, bool> BoolMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Node, bool, 
      BoolMatrixMap::Reference, BoolMatrixMap::ConstReference>,
      BoolMatrixMap>();

  }

  {
    Graph graph;
    typedef DynamicSymMatrixMap<Graph, Node, int> IntMatrixMap;
    IntMatrixMap matrix(graph);
    for (int i = 0; i < 10; ++i) {
      graph.addNode();
    }
    for (Graph::NodeIt it(graph); it != INVALID; ++it) {
      for (Graph::NodeIt jt(graph); jt != INVALID; ++jt) {
	int val = urandom(100);
	matrix.set(it, jt, val);
	check(matrix(it, jt) == val, "Wrong assign");
	check(matrix(jt, it) == val, "Wrong assign");
	check(matrix(it, jt) == matrixRowMap(matrix, it)[jt], "Wrong rowMap");
	check(matrix(it, jt) == matrixColMap(matrix, jt)[it], "Wrong colMap");
      }
    }
    const IntMatrixMap& cm = matrix;
    for (Graph::NodeIt it(graph); it != INVALID; ++it) {
      for (Graph::NodeIt jt(graph); jt != INVALID; ++jt) {
	check(cm(it, jt) == matrixRowMap(cm, it)[jt], "Wrong rowMap");
	check(cm(it, jt) == matrixColMap(cm, jt)[it], "Wrong colMap");
      }
    }
  }

  { // checking MatrixMap for int
    typedef DynamicAsymMatrixMap<Graph, Node, Graph, Edge, int> IntMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Edge, int, 
      IntMatrixMap::Reference, IntMatrixMap::ConstReference>,
      IntMatrixMap>();

  }

  { // checking MatrixMap for bool
    typedef DynamicAsymMatrixMap<Graph, Node, Graph, Edge, bool> BoolMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Edge, bool, 
      BoolMatrixMap::Reference, BoolMatrixMap::ConstReference>,
      BoolMatrixMap>();

  }

  {
    Graph graph1, graph2;
    typedef DynamicAsymMatrixMap<Graph, Node, Graph, Edge, int> IntMatrixMap;
    IntMatrixMap matrix(graph1, graph2);
    for (int i = 0; i < 10; ++i) {
      graph1.addNode();
    }
    graph2.addNode();
    for (int i = 0; i < 20; ++i) {
      graph2.addEdge(Graph::NodeIt(graph2), Graph::NodeIt(graph2));
    }
    for (Graph::NodeIt it(graph1); it != INVALID; ++it) {
      for (Graph::EdgeIt jt(graph2); jt != INVALID; ++jt) {
	int val = urandom(100);
	matrix.set(it, jt, val);
	check(matrix(it, jt) == val, "Wrong assign");
	check(matrix(it, jt) == matrixRowMap(matrix, it)[jt], "Wrong rowMap");
	check(matrix(it, jt) == matrixColMap(matrix, jt)[it], "Wrong colMap");
      }
    }
    const IntMatrixMap& cm = matrix;
    for (Graph::NodeIt it(graph1); it != INVALID; ++it) {
      for (Graph::EdgeIt jt(graph2); jt != INVALID; ++jt) {
	check(cm(it, jt) == matrixRowMap(cm, it)[jt], "Wrong rowMap");
	check(cm(it, jt) == matrixColMap(cm, jt)[it], "Wrong colMap");
      }
    }
  }

  { // checking MatrixMap for int
    typedef DynamicAsymMatrixMap<Graph, Node, Graph, Node, int> IntMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Node, int, 
      IntMatrixMap::Reference, IntMatrixMap::ConstReference>,
      IntMatrixMap>();

  }

  { // checking MatrixMap for bool
    typedef DynamicAsymMatrixMap<Graph, Node, Graph, Node, bool> BoolMatrixMap;
    checkConcept<ReferenceMatrixMap<Node, Node, bool, 
      BoolMatrixMap::Reference, BoolMatrixMap::ConstReference>,
      BoolMatrixMap>();

  }

  {
    Graph graph;
    typedef DynamicAsymMatrixMap<Graph, Node, Graph, Node, int> IntMatrixMap;
    IntMatrixMap matrix(graph, graph);
    for (int i = 0; i < 10; ++i) {
      graph.addNode();
    }
    for (int i = 0; i < 20; ++i) {
      graph.addEdge(Graph::NodeIt(graph), Graph::NodeIt(graph));
    }
    for (Graph::NodeIt it(graph); it != INVALID; ++it) {
      for (Graph::NodeIt jt(graph); jt != INVALID; ++jt) {
	int val = urandom(100);
	matrix.set(it, jt, val);
	check(matrix(it, jt) == val, "Wrong assign");
	check(matrix(it, jt) == matrixRowMap(matrix, it)[jt], "Wrong rowMap");
	check(matrix(it, jt) == matrixColMap(matrix, jt)[it], "Wrong colMap");
      }
    }
    const IntMatrixMap& cm = matrix;
    for (Graph::NodeIt it(graph); it != INVALID; ++it) {
      for (Graph::NodeIt jt(graph); jt != INVALID; ++jt) {
	check(cm(it, jt) == matrixRowMap(cm, it)[jt], "Wrong rowMap");
	check(cm(it, jt) == matrixColMap(cm, jt)[it], "Wrong colMap");
      }
    }
  }

  std::cout << __FILE__ ": All tests passed.\n";

  return 0;
}
