module JamRuby
  class BaseSearch < JsonStore

    attr_accessor :page_count, :results, :page_number

    ANY_VAL_STR = 'any'
    ANY_VAL_INT = -1

    VAL_YES = 'yes'
    VAL_NO = 'no'

    PER_PAGE = 10
    PG_SMALLINT_MAX = 32767

    KEY_SKILL = 'skill_level'
    KEY_GENRES = 'genres'
    KEY_INSTRUMENTS = 'instruments'
    KEY_GIGS = 'concert_gigs'
    KEY_SORT_ORDER = 'sort_order'

    SORT_VALS = %W{ latency distance }
    SORT_ORDERS = { 
      SORT_VALS[0] => 'Latency to Me', 
      SORT_VALS[1] => 'Distance to Me' 
    }

    SKILL_VALS = [ANY_VAL_INT, 1, 2]
    SKILL_LEVELS = { 
      SKILL_VALS[0] => 'Any', 
      SKILL_VALS[1] => 'Amateur',
      SKILL_VALS[2] => 'Pro', 
    }

    GIG_COUNTS = [ANY_VAL_INT, 0, 1, 2, 3, 4]
    GIG_LABELS = { 
      GIG_COUNTS[0] => 'Any',
      GIG_COUNTS[1] => 'under 10', 
      GIG_COUNTS[2] => '10 to 50', 
      GIG_COUNTS[3] => '50 to 100', 
      GIG_COUNTS[4] => 'over 100' 
    }

    INSTRUMENT_PROFICIENCY = {
      1 => 'Beginner',
      2 => 'Intermediate',
      3 => 'Expert',
    }

    def self.json_schema
      {
        KEY_SORT_ORDER => self::SORT_VALS[0],
        KEY_INSTRUMENTS => [],
        KEY_GENRES => [],
        KEY_GIGS => self::GIG_COUNTS[0].to_s,
      }
    end

    def self.search_filter_meta(jschema=nil, sort_order=nil)
      jschema ||= self.json_schema
      schema_keys = jschema.keys
      sort_order ||= { keys: self::SORT_VALS, map: self::SORT_ORDERS }
      multi_keys = jschema.collect { |kk,vv| vv.is_a?(Array) ? kk : nil }.compact
      {
        per_page: self::PER_PAGE,
        filter_keys: {
          keys: schema_keys,
          multi: multi_keys,
          single: schema_keys - multi_keys,
        },
        sort_order: sort_order
      }
    end

    RESULT_FOLLOW = :follows
    RESULT_FRIEND = :friends

    COUNT_FRIEND = :count_friend
    COUNT_FOLLOW = :count_follow
    COUNT_RECORD = :count_record
    COUNT_SESSION = :count_session
    COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION]

    def self.user_search_filter(user)
      unless ss = user.send(self.name.demodulize.tableize.singularize)
        ss = self.create_search(user)
      end
      ss
    end

    def self.search_filter_json(user)
      self.user_search_filter(user).json
    end

    def self.create_search(user)
      ms = self.new
      ms.user = user
      ms.data_blob = self.json_schema
      ms.save!
      ms
    end

    def self.search_target_class
    end

    def self.genre_ids
      @@genre_ids ||= Hash[ *Genre.pluck(:id).collect { |v| [ v, v ] }.flatten ]
    end

    def self.instrument_ids
      @@instrument_ids ||= Hash[ *Instrument.pluck(:id).collect { |v| [ v, v ] }.flatten ]
    end

    def _genres(rel, query_data=json)
      gids = query_data[KEY_GENRES]
      unless gids.blank?
        allgids = self.class.genre_ids
        gids = gids.select { |gg| allgids.has_key?(gg) }
        
        unless gids.blank?
          gidsql = gids.join("','")
          gpsql = "SELECT player_id FROM genre_players WHERE (player_type = '#{self.class.search_target_class.name}' AND genre_id IN ('#{gidsql}'))"
          rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{gpsql})")
        end
      end
      rel
    end

    def _instruments(rel, query_data=json)
      unless (instruments = query_data[KEY_INSTRUMENTS]).blank?
        instrids = self.class.instrument_ids
        instruments = instruments.select { |ii| instrids.has_key?(ii['instrument_id']) }

        unless instruments.blank?
          instsql = "SELECT player_id FROM musicians_instruments WHERE (("
          instsql += instruments.collect do |inst|
            unless MusicianInstrument::PROFICIENCY_RANGE === (proflvl=inst['proficiency_level'].to_i) 
              proflvl = MusicianInstrument::LEVEL_INTERMEDIATE 
            end
            "instrument_id = '#{inst['instrument_id']}' AND proficiency_level = #{proflvl}"
          end.join(") OR (")
          instsql += "))"

          rel = rel.where("#{self.class.search_target_class.table_name}.id IN (#{instsql})")
        end
      end
      rel
    end
    
    def _gigs(rel)
      gg = json[KEY_GIGS].to_i
      rel = rel.where('concert_count = ?',gg) if 0 <= gg
      rel
    end

    def _skills(rel)
      if 0 < (val = json[KEY_SKILL].to_i)
        rel = rel.where(['skill_level = ?', val])
      end
      rel
    end

    def _sort_order(rel)
    end

    def do_search(params={}) 
    end

    def process_results_page(objs)
    end

    def search_includes(rel)
      rel
    end

    def search_results_page(filter=nil, page=1)
      if filter
        self.data_blob = filter
        self.save
      else
        filter = self.data_blob
      end

      rel = do_search(filter)

      @page_number = [page.to_i, 1].max
      rel = rel.paginate(:page => @page_number, :per_page => self.class::PER_PAGE)

      rel = self.search_includes(rel)
      @page_count = rel.total_pages

      process_results_page(rel.all)
    end
    
    def reset_filter
      self.data_blob = self.class.json_schema
      self.save
    end

    def reset_search_results
      reset_filter
      search_results_page
    end

    def search_type
      self.class.to_s
    end

    def is_blank?
      self.data_blob == self.class.json_schema
    end

    def description
    end

  end
end
