class DataCollector(object):
    """The DataCollector collects and stores all data.

    The stored data includes:
        - Time
        - GPS data
        - OBD2 data
    """

    def __init__(self):
        """Initializes the DataCollector."""
        super(DataCollector, self).__init__()
        
        obd2readerClass  = getattr(obd2reader, CONFIGURATION["obd2reader"])
        self._obd2reader = obd2readerClass(CONFIGURATION["device"], CONFIGURATION["speed"])
        self._obd2reader.open_connection()

        self._gpsreader  = GPSReader(CONFIGURATION["gpsdPort"])

    def shutdown(self):
        """Shuts down the DataCollector and all of its Threads."""
        self._obd2reader.shutdown()
        self._gpsreader.shutdown()

    def write_data_log(self, logFileName, nbrOfOBDFrames, messagesPerTimestamp):
        """Stores an data log file to the given location.

        :param String  logFileName:             Path to store the log file.
        :param Integer nbrOfOBDFrames:          Number of OBD frames to be stored inside the log.
                                                This parameter does NOT affect the number of time
                                                stamps or GPS reports.
        :param Integer messagesPerTimestamp:    Number of OBD2 frames share the same time stamp.

        :return:    Returns the number of bytes stored in the log.
        :rtype:     Integer
        """
        ## create the log file
        logf  = file(logFileName, "ab")
        
        ## performance optimization
        ## reduces the __getattr__ calls for the major instances
        write      = logf.write
        gpsreader  = self._gpsreader
        obd2reader = self._obd2reader

        ## number of bytes written
        bytes = 0

        ## collect the requested number of OBD2 frames
        for idx in xrange(0, nbrOfOBDFrames, messagesPerTimestamp):

            ## time stamp
            timestamp = "#TIME__%s\n" % _getCurrentTime()
            write(timestamp)
            bytes += len(timestamp)

            ## read the number of frames requested
            try:
                logEntries = obd2reader.read_frames(nbrOfOBDFrames)
            except:
                obd2reader.reconnect()
                continue
            
            ## store the frames in the log
            logEntries = "\n".join(logEntries)
            write("%s\n" % logEntries)
            bytes += len(logEntries) + 1

            ## append the gpslog entries, when there are any
            gpsreports = ["#GPS__%s\n" % entry for entry in gpsreader.get_current_gps_entries()]
            
            ## no GPS report collected since last run
            if not gpsreports:
                continue

            ## store the reports in the log
            gpsreports = "\n".join([str(r) for r in gpsreports])
            write("%s\n" % gpsreports)
            bytes += len(gpsreports) + 1


        # close the log file
        logf.close()
        
        ## return the number of bytes written
        return bytes