# Path: haystack/search/searcher.py
# class RecordSearcher(object):
# class RecordLoader(RecordSearcher):
# class AnyOffsetRecordSearcher(RecordSearcher):
#     def __init__(self, memory_handler, my_constraints=None, target_mappings=None, update_cb=None):
#     def search(self, struct_type, max_res=10, max_depth=10):
#     def _search_in(self, mem_map, struct_type, nb=10, depth=99):
#     def _load_at(self, mem_map, address, struct_type, depth=99):
#     def load(self, struct_type, memory_address):
#     def __init__(self, memory_handler, my_constraints=None, target_mappings=None, update_cb=None):
#     def _search_in(self, mem_map, struct_type, nb=10, depth=99, align=None):
# 
# Path: haystack/outputters/text.py
# class RecursiveTextOutputter(Outputter):
#     def parse(self, obj, prefix='', depth=10, addr_was=None):
#     def _attrToString(self, attr, field, attrtype, prefix, addr, depth=-1):
# 
# Path: haystack/outputters/python.py
# class PythonOutputter(Outputter):
# class pyObj(object):
# class _pyObjBuilder:
#     def parse(self, obj, prefix='', depth=50):
#     def _attrToPyObject(self, attr, field, attrtype):
# def json_encode_pyobj(obj):
#     def toString(self, prefix='', maxDepth=10):
#     def _attrToString(self, attr, attrname, typ, prefix, maxDepth):
#     def __len__(self):
#     def findCtypes(self, cache=None):
#     def _attrFindCtypes(self, attr, attrname, typ, cache):
#     def __iter__(self):
#     def __getstate__(self):
#     def __reduce__(self):
#     def __call__(self, modulename, classname):
# def findCtypesInPyObj(memory_handler, obj):
# 
# Path: haystack/listmodel.py
# class ListModel(basicmodel.CTypesRecordConstraintValidator):
#     def is_single_linked_list_type(self, record_type):
#     def is_double_linked_list_type(self, record_type):
#     def get_single_linked_list_type(self, record_type):
#     def get_double_linked_list_type(self, record_type):
#     def register_single_linked_list_record_type(self, record_type, forward, sentinels=None):
#     def register_double_linked_list_record_type(self, record_type, forward, backward, sentinels=None):
#     def register_linked_list_field_and_type(self, record_type, field_name, list_entry_type, list_entry_field_name):
#     def _get_list_info_for_field_for(self, record_type, fieldname):
#     def _get_list_fields(self, record_type):
#     def iterate_list_from_field(self, record, fieldname, sentinels=None, ignore_head=True):
#     def iterate_list_from_pointer_field(self, pointer_field, target_fieldname, sentinels=None):
#     def _iterate_list_from_field_with_link_info(self, record, link_info, sentinels=None, ignore_head=True):
#     def _iterate_list_from_field_inner(self, iterator_fn, head, pointee_record_type, offset, sentinels):
#     def _iterate_double_linked_list(self, record, sentinels=None):
#     def _iterate_single_linked_list(self, record, sentinels=None):
#     def is_valid(self, record):
#     def load_members(self, record, max_depth):
#     def _load_list_entries(self, record, link_iterator, max_depth):


from past.builtins import long
from haystack.search import searcher
from haystack.outputters import text
from haystack.outputters import python
from haystack import listmodel
import logging
import pickle
import json
    If constraints exists, they will be considered during the search.

    :param memory_handler: IMemoryHandler
    :param record_type: a ctypes.Structure or ctypes.Union from a module imported by haystack
    :param search_constraints: IModuleConstraints to be considered during the search
    :param extended_search: boolean, use allocated chunks only per default (False)
    :rtype a list of (ctypes records, memory offset)
    """
    hint_mapping = memory_handler.get_mapping_for_address(hint)
    if extended_search:
        my_searcher = searcher.AnyOffsetRecordSearcher(memory_handler,
                                                       my_constraints=search_constraints,
                                                       target_mappings=[hint_mapping])
        return my_searcher.search(record_type)
    my_searcher = searcher.RecordSearcher(memory_handler,
                                          my_constraints=search_constraints,
                                          target_mappings=[hint_mapping])
    return my_searcher.search(record_type)


# FIXME TODO change for results == ctypes
def output_to_string(memory_handler, results):
    """
    Transform ctypes results in a string format
    :param memory_handler: IMemoryHandler
    :param results: results from the search_record
    :return:
    """
    if not isinstance(results, list):
        raise TypeError('Feed me a list of results')

# Path: haystack/search/searcher.py
# class RecordSearcher(object):
# class RecordLoader(RecordSearcher):
# class AnyOffsetRecordSearcher(RecordSearcher):
#     def __init__(self, memory_handler, my_constraints=None, target_mappings=None, update_cb=None):
#     def search(self, struct_type, max_res=10, max_depth=10):
#     def _search_in(self, mem_map, struct_type, nb=10, depth=99):
#     def _load_at(self, mem_map, address, struct_type, depth=99):
#     def load(self, struct_type, memory_address):
#     def __init__(self, memory_handler, my_constraints=None, target_mappings=None, update_cb=None):
#     def _search_in(self, mem_map, struct_type, nb=10, depth=99, align=None):
# 
# Path: haystack/outputters/text.py
# class RecursiveTextOutputter(Outputter):
#     def parse(self, obj, prefix='', depth=10, addr_was=None):
#     def _attrToString(self, attr, field, attrtype, prefix, addr, depth=-1):
# 
# Path: haystack/outputters/python.py
# class PythonOutputter(Outputter):
# class pyObj(object):
# class _pyObjBuilder:
#     def parse(self, obj, prefix='', depth=50):
#     def _attrToPyObject(self, attr, field, attrtype):
# def json_encode_pyobj(obj):
#     def toString(self, prefix='', maxDepth=10):
#     def _attrToString(self, attr, attrname, typ, prefix, maxDepth):
#     def __len__(self):
#     def findCtypes(self, cache=None):
#     def _attrFindCtypes(self, attr, attrname, typ, cache):
#     def __iter__(self):
#     def __getstate__(self):
#     def __reduce__(self):
#     def __call__(self, modulename, classname):
# def findCtypesInPyObj(memory_handler, obj):
# 
# Path: haystack/listmodel.py
# class ListModel(basicmodel.CTypesRecordConstraintValidator):
#     def is_single_linked_list_type(self, record_type):
#     def is_double_linked_list_type(self, record_type):
#     def get_single_linked_list_type(self, record_type):
#     def get_double_linked_list_type(self, record_type):
#     def register_single_linked_list_record_type(self, record_type, forward, sentinels=None):
#     def register_double_linked_list_record_type(self, record_type, forward, backward, sentinels=None):
#     def register_linked_list_field_and_type(self, record_type, field_name, list_entry_type, list_entry_field_name):
#     def _get_list_info_for_field_for(self, record_type, fieldname):
#     def _get_list_fields(self, record_type):
#     def iterate_list_from_field(self, record, fieldname, sentinels=None, ignore_head=True):
#     def iterate_list_from_pointer_field(self, pointer_field, target_fieldname, sentinels=None):
#     def _iterate_list_from_field_with_link_info(self, record, link_info, sentinels=None, ignore_head=True):
#     def _iterate_list_from_field_inner(self, iterator_fn, head, pointee_record_type, offset, sentinels):
#     def _iterate_double_linked_list(self, record, sentinels=None):
#     def _iterate_single_linked_list(self, record, sentinels=None):
#     def is_valid(self, record):
#     def load_members(self, record, max_depth):
#     def _load_list_entries(self, record, link_iterator, max_depth):


# Path: haystack/search/api.py
from past.builtins import long
from haystack.search import searcher
from haystack.outputters import text
from haystack.outputters import python
from haystack import listmodel
import logging
import pickle
import json

    If constraints exists, they will be considered during the search.

    :param memory_handler: IMemoryHandler
    :param record_type: a ctypes.Structure or ctypes.Union from a module imported by haystack
    :param search_constraints: IModuleConstraints to be considered during the search
    :param extended_search: boolean, use allocated chunks only per default (False)
    :rtype a list of (ctypes records, memory offset)
    """
    hint_mapping = memory_handler.get_mapping_for_address(hint)
    if extended_search:
        my_searcher = searcher.AnyOffsetRecordSearcher(memory_handler,
                                                       my_constraints=search_constraints,
                                                       target_mappings=[hint_mapping])
        return my_searcher.search(record_type)
    my_searcher = searcher.RecordSearcher(memory_handler,
                                          my_constraints=search_constraints,
                                          target_mappings=[hint_mapping])
    return my_searcher.search(record_type)


# FIXME TODO change for results == ctypes
def output_to_string(memory_handler, results):
    """
    Transform ctypes results in a string format
    :param memory_handler: IMemoryHandler
    :param results: results from the search_record
    :return:
    """
    if not isinstance(results, list):
        raise TypeError('Feed me a list of results')

    parser = text.RecursiveTextOutputter(memory_handler)