#    Copyright 2017 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import division
import csv
import re

from devlib.platform.gem5 import Gem5SimulationPlatform
from devlib.instrument import Instrument, CONTINUOUS, MeasurementsCsv
from devlib.exception import TargetError, HostError


class Gem5PowerInstrument(Instrument):
    '''
    Instrument enabling power monitoring in gem5
    '''

    mode = CONTINUOUS
    roi_label = 'power_instrument'
    site_mapping = {'timestamp': 'sim_seconds'}

    def __init__(self, target, power_sites):
        '''
        Parameter power_sites is a list of gem5 identifiers for power values.
        One example of such a field:
            system.cluster0.cores0.power_model.static_power
        '''
        if not isinstance(target.platform, Gem5SimulationPlatform):
            raise TargetError('Gem5PowerInstrument requires a gem5 platform')
        if not target.has('gem5stats'):
            raise TargetError('Gem5StatsModule is not loaded')
        super(Gem5PowerInstrument, self).__init__(target)

        # power_sites is assumed to be a list later
        if isinstance(power_sites, list):
            self.power_sites = power_sites
        else:
            self.power_sites = [power_sites]
        self.add_channel('timestamp', 'time')
        for field in self.power_sites:
            self.add_channel(field, 'power')
        self.target.gem5stats.book_roi(self.roi_label)
        self.sample_period_ns = 10000000
        # Sample rate must remain unset as gem5 does not provide samples
        # at regular intervals therefore the reported timestamp should be used.
        self.sample_rate_hz = None
        self.target.gem5stats.start_periodic_dump(0, self.sample_period_ns)
        self._base_stats_dump = 0

    def start(self):
        self.target.gem5stats.roi_start(self.roi_label)

    def stop(self):
        self.target.gem5stats.roi_end(self.roi_label)

    def get_data(self, outfile):
        active_sites = [c.site for c in self.active_channels]
        with open(outfile, 'wb') as wfh:
            writer = csv.writer(wfh)
            writer.writerow([c.label for c in self.active_channels]) # headers
            sites_to_match = [self.site_mapping.get(s, s) for s in active_sites]
            for rec, rois in self.target.gem5stats.match_iter(sites_to_match,
                    [self.roi_label], self._base_stats_dump):
                writer.writerow([rec[s] for s in active_sites])
        return MeasurementsCsv(outfile, self.active_channels, self.sample_rate_hz)

    def reset(self, sites=None, kinds=None, channels=None):
        super(Gem5PowerInstrument, self).reset(sites, kinds, channels)
        self._base_stats_dump = self.target.gem5stats.next_dump_no()

