text: #!/usr/bin/python
  # -*- coding: utf-8 -*-
  #  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 datetime import datetime
  from github import mstr
  from jira_github import Jira
  from formatter import Formatter, encode
  
  
  def daydiff(a, b):
      return (a - b).days
  
  
  class Report:
      now = datetime.utcnow()
      def __init__(self, header=''):
          self.header = header
  
      # if padding starts with - it puts padding before contents, otherwise after
      @staticmethod
      def _build_tuple(contents, padding=''):
          if padding is not '':
              out = []
              for i in range(len(contents)):
                  out += [padding[1:] + str(contents[i])] if padding[0] is '-' else [str(contents[i]) + padding]
              return tuple(out)
          return contents
  
      # calls the native print function with the following format. Text1,Text2,... has the correct spacing
      # print ("%s%s%s" % ("Text1, Text2, Text3))
      def print_(self, formatter, row_tuple):
          print (formatter.format % formatter.row_str_format(row_tuple))
  
  class JiraReport(Report):
      def __init__(self, issues, header=''):
          Report.__init__(self, header)
          self.issues = issues
  
      def view(self, excluded):
          issues_view = dict(self.issues)
          for key in excluded:
              issues_view.pop(key, None)
          return issues_view
  
      def keys_view(self, excluded):
          return self.view(excluded).keys().sort(Jira.storm_jira_cmp, reverse=True)
  
      def values_view(self, excluded=None):
          temp_dic = dict(self.issues) if excluded is None else self.view(excluded)
          values = temp_dic.values()
          values.sort(Jira.storm_jira_cmp, reverse=True)
          return values
  
      @staticmethod
      def _row_tuple(jira):
          return (jira.get_id(), jira.get_trimmed_summary(), daydiff(Report.now, jira.get_created()),
                  daydiff(Report.now, jira.get_updated()))
  
      def _min_width_tuple(self):
          return -1, 43, -1, -1
  
      def print_report(self):
          print "%s (Count = %s) " % (self.header, len(self.issues))
          jiras = self.values_view()
          fields_tuple = ('Jira Id', 'Summary', 'Created', 'Last Updated (Days)')
          row_tuple = self._row_tuple(jiras[0])
  
          formatter = Formatter(fields_tuple, row_tuple, self._min_width_tuple())
  
          self.print_(formatter, fields_tuple)
  
          for jira in jiras:
              row_tuple = self._row_tuple(jira)
              self.print_(formatter, row_tuple)
  
      @staticmethod
      def build_jira_url(jira_id):
          BASE_URL = "https://issues.apache.org/jira/browse/"
          return BASE_URL + jira_id
  
  
  class GitHubReport(Report):
      def __init__(self, pull_requests=None, header=''):
          Report.__init__(self, header)
  
          if pull_requests is None:
              self.pull_requests = []
              self.type = ''
          else:
              self.pull_requests = pull_requests
              self.type = type
  
      def _row_tuple(self, pull):
          return self._build_tuple(
              (pull.html_url(), pull.trimmed_title(), daydiff(Report.now, pull.created_at()),
               daydiff(Report.now, pull.updated_at()), pull.user()), '')
  
      def _min_width_tuple(self):
          return -1, 43, -1, -1, -1
  
      def print_report(self):
          print "%s (Count = %s) " % (self.header, len(self.pull_requests))
  
          fields_tuple = self._build_tuple(('URL', 'Title', 'Created', 'Last Updated (Days)', 'User'), '')
          if len(self.pull_requests) > 0:
              row_tuple = self._row_tuple(self.pull_requests[0])
  
              formatter = Formatter(fields_tuple, row_tuple, self._min_width_tuple())
  
              self.print_(formatter, fields_tuple)
              for pull in self.pull_requests:
                  row_tuple = self._row_tuple(pull)
                  self.print_(formatter, row_tuple)
  
      def jira_ids(self):
          """
          :return: sorted list of JIRA ids present in Git pull requests
          """
          jira_ids = list()
          for pull in self.pull_requests:
              jira_ids.append(pull.jira_id())
          return sorted(jira_ids)
  
  class JiraGitHubCombinedReport(Report):
      def __init__(self, jira_report, github_report, header='', print_comments=False):
          Report.__init__(self, header)
          self.jira_report = jira_report
          self.github_report = github_report
          self.print_comments = print_comments
  
      def _jira_comments(self, jira_id):
          return None if jira_id is None else self.jira_report.issues[jira_id].get_comments()
  
      def _idx_1st_comment_with_vote(self):
          g = 0
          for pull in self.github_report.pull_requests:
              c = 0
              for comment in self._jira_comments(pull.jira_id()):
                  if comment.has_vote():
                      return(g,) + (c,)
                  c += 1
              g += 1
  
      def _pull_request(self, pull_idx):
          pull = self.github_report.pull_requests[pull_idx]
          return pull
  
      def _jira_id(self, pull_idx):
          pull = self._pull_request(pull_idx)
          return encode(pull.jira_id())
  
      def _jira_issue(self, jira_id):
          return self.jira_report.issues[jira_id]
  
      def _row_tuple(self, pull_idx):
          pull = self._pull_request(pull_idx)
          jira_id = self._jira_id(pull_idx)
          jira_issue = self._jira_issue(jira_id)
  
          return (jira_id, mstr(pull), jira_issue.get_trimmed_summary(),
                  daydiff(Report.now, jira_issue.get_created()),
                  daydiff(Report.now, pull.created_at()),
                  daydiff(Report.now, jira_issue.get_updated()),
                  daydiff(Report.now, pull.updated_at()),
                  jira_issue.get_status(), pull.user())
  
      def _row_tuple_1(self, pull_idx, comment_idx):
          row_tuple_1 = None
          jira_id = self._jira_id(pull_idx)
          jira_comments = self._jira_comments(jira_id)
          comment = jira_comments[comment_idx]
          if comment.has_vote():
              row_tuple_1 = (comment.get_vote(), comment.get_author(), comment.get_pull(),
                             daydiff(Report.now, comment.get_created()))
  
          return row_tuple_1
  
      # variables and method names ending with _1 correspond to the comments part
      def print_report(self, print_comments=False):
          print "%s (Count = %s) " % (self.header, len(self.github_report.pull_requests))
  
          fields_tuple = ('JIRA ID', 'Pull Request', 'Jira Summary', 'JIRA Age',
                          'Pull Age', 'JIRA Update Age', 'Pull Update Age (Days)',
                          'JIRA Status', 'GitHub user')
          row_tuple = self._row_tuple(0)
          formatter = Formatter(fields_tuple, row_tuple)
          self.print_(formatter, fields_tuple)
  
          row_tuple_1 = ()
          formatter_1 = Formatter()
  
          if print_comments or self.print_comments:
              fields_tuple_1 = self._build_tuple(('Comment Vote', 'Comment Author', 'Pull URL', 'Comment Age'), '-\t\t')
              row_tuple_1 = self._build_tuple(self._row_tuple_1(*self._idx_1st_comment_with_vote()), '-\t\t')
              formatter_1 = Formatter(fields_tuple_1, row_tuple_1)
              self.print_(formatter_1, fields_tuple_1)
              print ''
  
          for p in range(0, len(self.github_report.pull_requests)):
              row_tuple = self._row_tuple(p)
              self.print_(formatter, row_tuple)
  
              if print_comments or self.print_comments:
                  has_vote = False
                  comments = self._jira_comments(self._jira_id(p))
                  for c in range(len(comments)):     # Check cleaner way
                      comment = comments[c]
                      if comment.has_vote():
                          row_tuple_1 = self._build_tuple(self._row_tuple_1(p, c), '-\t\t')
                          if row_tuple_1 is not None:
                              self.print_(formatter_1, row_tuple_1)
                              has_vote = True
                  if has_vote:
                      print ''
  
  
  class CompleteReport(Report):
      def __init__(self, header=''):
          Report.__init__(self, header)
          self.jira_reports = []
          self.github_reports = []
          self.jira_github_combined_reports = []
  
      def print_all(self):
          if self.header is not '':
              print self.header
  
          self._print_github_reports()
          self._print_jira_github_combined_reports()
          self._print_jira_reports()
  
      def _print_jira_reports(self):
          for jira in self.jira_reports:
              jira.print_report()
  
      def _print_github_reports(self):
          for github in self.github_reports:
              github.print_report()
  
      def _print_jira_github_combined_reports(self):
          for jira_github_combined in self.jira_github_combined_reports:
              jira_github_combined.print_report()
  