//=-- FilterManager.cpp - Maintains filter, creates and destroys filters -----=
//
//  The class is used to cache filter objects so that only one for each filter
//  exists.  This ensures that the individual filter objects can accomplish
//  their caching strategies effectively.
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-1998 Chris Lattner
//=---------------------------------------------------------------------------=

#include "FilterManager.h"
#include "Table.h"
#include "VarTable.h"

// Instantiate static FilterList
LinkedList<FilterHandle> FilterManager::FilterList;

// Get a filter, when you know the I and E portions of the filter spec 
// explicitly...
//
FilterHandle FilterManager::GetFilter(const String &I, const String &E) {
  LLLink<FilterHandle> *Link;
  FilterHandle FNew;

  String S = I + ":" + E;                   // Create our query string
  
  Link = FilterList.SearchList(S);          // See if the filter already exists

  if (Link != 0) {
    FNew = Link->Data;                      // Yup, get the filter

  } else {                                  // Nope...
    FNew = FilterHandle(new Filter(I, E));  // Create new filter.
    FilterList.AddToHead(FNew);             // Add it to the list
  }

  return FNew;
}


// Get a filter, when you have a list of two elements, corresponding the the
// include and exclude portions of the filter.
//
FilterHandle FilterManager::GetFilter(VTListExp *FilterSpec) {
  VTExp *I = 0, *E = 0;

  switch (FilterSpec->GetNumElements()) {
  case 0:                                 // Null filter, matches everything...
    return GetFilter(String("*"), String(""));
  case 1:
    I = FilterSpec->GetListElement(0);

    if (I && I->GetExpType() == VTExp::StringTy)
      return GetFilter(I->GetStringValue(), String(""));
    break;
  case 2:
    I = FilterSpec->GetListElement(0);
    E = FilterSpec->GetListElement(1);

    if (I && I->GetExpType() == VTExp::StringTy &&
        E && E->GetExpType() == VTExp::StringTy)
      return GetFilter(I->GetStringValue(), E->GetStringValue());
    break;
  }

  cout << "Malformed filter specification: " << FilterSpec;
  if (FilterSpec->GetLineNo() != -1)  
    cout << ": Line #" << FilterSpec->GetLineNo();
  cout << "\n";
  
  return GetFilter("*", "");
}


// Get a filter, when you have a list of two elements, corresponding the the
// include and exclude portions of the filter.
//
FilterHandle FilterManager::GetFilter(VarTable *List, const String &KeyName) {
  String Include, Exclude;

  if (List->InTable(KeyName)) {
    VTExp *Value = (*List)[KeyName];

    // Is the filter a string value?
    if (Value->GetExpType() == VTExp::StringTy) {
      String Temp = Value->GetStringValue();
      if (Temp.GetParameter(Include)) {
        cout << "Malformed " << KeyName << " parameter!\n";
        return GetFilter();
      }

      if (Temp.GetParameter(Exclude)) 
        Exclude = "";
    } else {
      return GetFilter((VTListExp*)Value);
    }
  } else  {
    Include = "*";
    Exclude = "";
  } 

  return GetFilter(Include, Exclude);
}
