//  Clint - Source code checker for C++
//  Copyright (C) 2001  David Pashley
//
//  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
#include <algorithm>
#include <functional>
#include <vector>
#include <deque>
#include <string> 
#include <dlfcn.h> 
#include <dirent.h>
#include "plugin.h"
#include <stdexcept>
#include "rule.h"
#include <iostream> 
#include <fstream>
#include "utility.h"
#include <debug.h>
#include "message.h"
#include "input.h"

/*! \var vector<Plugin *> plugins
 * our global list of plugin
 * \warning not thread safe
 */
std::vector<Plugin *> plugins;
RuleList rules;

using clint::Input;

int main(int argc, char * argv[])
{
   std::deque<std::string> args(argv, argv+argc);
   clint::parse_args(args);

   if (args.size()==2) {
      Input::instance()->set_input(args[1]);
   } 

   try {

      std::vector<std::string> plugin_files;
      clint::get_plugin_list(plugin_files,".");
      clint::get_plugin_list(plugin_files,clint::find_home()+"/.clint/plugins");
      clint::get_plugin_list(plugin_files,PKGLIBDIR);

      std::vector<void *> dl_list; // list to hold handles
      for (std::vector<std::string>::iterator cur_plugin = plugin_files.begin(); cur_plugin != plugin_files.end(); cur_plugin++ ) {
         void *dlib = dlopen(cur_plugin->c_str(), RTLD_NOW);
         if(dlib == NULL){
            std::cerr << dlerror() << std::endl; 
            exit(-1);
         }
         // add the handle to our list
         dl_list.push_back(dlib);
      }

      // Initialise all the plugins
      for_each(plugins.begin(), plugins.end(),std::mem_fun(&Plugin::initialize) );

      // get all the Rules
      for (std::vector<Plugin *>::iterator cur_plugin = plugins.begin(); cur_plugin != plugins.end(); cur_plugin++ ) {
         (*cur_plugin)->register_rules(rules);
      }

      // Initialise all the rules
      for_each(rules.begin(), rules.end(),std::mem_fun(&Rule::initialize) );

      while (not Input::instance()->eof()) {
         clint::Pair cur_line;
         cur_line = Input::instance()->getline();
         for (RuleList::iterator cur_rule = rules.begin(); cur_rule != rules.end(); cur_rule++ ) {
            (*cur_rule)->pre_cpp(cur_line.first);
         }
         for (RuleList::iterator cur_rule = rules.begin(); cur_rule != rules.end(); cur_rule++ ) {
            (*cur_rule)->post_cpp(cur_line.second);
         }
      }

      // Finalise the rules
      for_each(rules.begin(), rules.end(),std::mem_fun(&Rule::finalize) );


      // Finalise all the plugins
      for_each(plugins.begin(), plugins.end(),std::mem_fun(&Plugin::finalize) );

      // close all the libraries //
      for_each(dl_list.begin(),dl_list.end(),dlclose);

      // sort the messages and then print it
      std::sort(clint::msgs.begin(), clint::msgs.end());
      std::cerr << clint::msgs;

   } catch (std::exception & e) {
      std::cout << "WARNING: caught an exception: " << e.what() << std::endl;
      throw;
   } catch (...) {
      std::cout << "WARNING: caught an unknown exception" << std::endl;
      throw;
   }
   return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1