text: # -*- coding: utf-8 -*-
  
  #    Copyright 2013 Mirantis, Inc.
  #
  #    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.
  
  import codecs
  import cStringIO
  import csv
  from hashlib import md5
  import tempfile
  
  import web
  
  from nailgun import objects
  
  from nailgun.api.v1.handlers.base import BaseHandler
  from nailgun.api.v1.handlers.base import content
  from nailgun.task.manager import GenerateCapacityLogTaskManager
  
  
  """
  Capacity audit handlers
  """
  
  
  class UnicodeWriter(object):
      """Unicode CSV writer.
  
      A CSV writer which will write rows to CSV file "f",
      which is encoded in the given encoding.
      Source: http://docs.python.org/2/library/csv.html#examples
      """
  
      def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
          # Redirect output to a queue
          self.queue = cStringIO.StringIO()
          self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
          self.stream = f
          self.encoder = codecs.getincrementalencoder(encoding)()
  
      def writerow(self, row):
          # We have only string and int types in capacity log now.
          # Don't need to convert int values to string for writhing it to file.
          self.writer.writerow(
              [s.encode("utf-8") if type(s) != int else s for s in row])
          # Fetch UTF-8 output from the queue ...
          data = self.queue.getvalue()
          data = data.decode("utf-8")
          # ... and reencode it into the target encoding
          data = self.encoder.encode(data)
          # write to the target stream
          self.stream.write(data)
          # empty queue
          self.queue.truncate(0)
  
      def writerows(self, rows):
          for row in rows:
              self.writerow(row)
  
  
  class CapacityLogHandler(BaseHandler):
      """Task single handler"""
  
      fields = (
          "id",
          "report"
      )
  
      @content
      def GET(self):
          capacity_log = objects.CapacityLog.get_latest()
          if not capacity_log:
              raise self.http(404)
          return self.render(capacity_log)
  
      @content
      def PUT(self):
          """Starts capacity data generation.
  
          :returns: JSONized Task object.
          :http: * 200 (setup task successfully executed)
                 * 202 (setup task created and started)
                 * 400 (data validation failed)
                 * 404 (cluster not found in db)
          """
          # TODO(pkaminski): this seems to be synchronous, no task needed here
          manager = GenerateCapacityLogTaskManager()
          task = manager.execute()
  
          self.raise_task(task)
  
  
  class CapacityLogCsvHandler(BaseHandler):
  
      def GET(self):
          capacity_log = objects.CapacityLog.get_latest()
          if not capacity_log:
              raise self.http(404)
  
          report = capacity_log.report
          f = tempfile.TemporaryFile(mode='r+b')
          csv_file = UnicodeWriter(f, delimiter=',',
                                   quotechar='|', quoting=csv.QUOTE_MINIMAL)
  
          csv_file.writerow(['Fuel version', report['fuel_data']['release']])
          csv_file.writerow(['Fuel UUID', report['fuel_data']['uuid']])
  
          csv_file.writerow(['Environment Name', 'Node Count'])
          for stat in report['environment_stats']:
              csv_file.writerow([stat['cluster'], stat['nodes']])
  
          csv_file.writerow(['Total number allocated of nodes',
                             report['allocation_stats']['allocated']])
          csv_file.writerow(['Total number of unallocated nodes',
                             report['allocation_stats']['unallocated']])
  
          csv_file.writerow([])
          csv_file.writerow(['Node role(s)',
                             'Number of nodes with this configuration'])
          for roles, count in report['roles_stat'].iteritems():
              csv_file.writerow([roles, count])
  
          f.seek(0)
          checksum = md5(f.read()).hexdigest()
          csv_file.writerow([])
          csv_file.writerow(['Checksum', checksum])
  
          filename = 'fuel-capacity-audit.csv'
          web.header('Content-Type', 'application/octet-stream')
          web.header('Content-Disposition', 'attachment; filename="%s"' % (
              filename))
          web.header('Content-Length', f.tell())
          f.seek(0)
          return f
  