# Copyright (C) 2012 The Android Open Source Project
#
# 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 optparse

from command import PagedCommand
from color import Coloring
from git_refs import R_M, R_HEADS


class _Coloring(Coloring):
  def __init__(self, config):
    Coloring.__init__(self, config, "status")


class Info(PagedCommand):
  COMMON = True
  helpSummary = "Get info on the manifest branch, current branch or unmerged branches"
  helpUsage = "%prog [-dl] [-o [-c]] [<project>...]"

  def _Options(self, p):
    p.add_option('-d', '--diff',
                 dest='all', action='store_true',
                 help="show full info and commit diff including remote branches")
    p.add_option('-o', '--overview',
                 dest='overview', action='store_true',
                 help='show overview of all local commits')
    p.add_option('-c', '--current-branch',
                 dest="current_branch", action="store_true",
                 help="consider only checked out branches")
    p.add_option('--no-current-branch',
                 dest='current_branch', action='store_false',
                 help='consider all local branches')
    # Turn this into a warning & remove this someday.
    p.add_option('-b',
                 dest='current_branch', action='store_true',
                 help=optparse.SUPPRESS_HELP)
    p.add_option('-l', '--local-only',
                 dest="local", action="store_true",
                 help="disable all remote operations")

  def Execute(self, opt, args):
    self.out = _Coloring(self.client.globalConfig)
    self.heading = self.out.printer('heading', attr='bold')
    self.headtext = self.out.nofmt_printer('headtext', fg='yellow')
    self.redtext = self.out.printer('redtext', fg='red')
    self.sha = self.out.printer("sha", fg='yellow')
    self.text = self.out.nofmt_printer('text')
    self.dimtext = self.out.printer('dimtext', attr='dim')

    self.opt = opt

    if not opt.this_manifest_only:
      self.manifest = self.manifest.outer_client
    manifestConfig = self.manifest.manifestProject.config
    mergeBranch = manifestConfig.GetBranch("default").merge
    manifestGroups = self.manifest.GetGroupsStr()

    self.heading("Manifest branch: ")
    if self.manifest.default.revisionExpr:
        self.headtext(self.manifest.default.revisionExpr)
    self.out.nl()
    self.heading("Manifest merge branch: ")
    self.headtext(mergeBranch)
    self.out.nl()
    self.heading("Manifest groups: ")
    self.headtext(manifestGroups)
    self.out.nl()

    self.printSeparator()

    if not opt.overview:
      self._printDiffInfo(opt, args)
    else:
      self._printCommitOverview(opt, args)

  def printSeparator(self):
    self.text("----------------------------")
    self.out.nl()

  def _printDiffInfo(self, opt, args):
    # We let exceptions bubble up to main as they'll be well structured.
    projs = self.GetProjects(args, all_manifests=not opt.this_manifest_only)

    for p in projs:
      self.heading("Project: ")
      self.headtext(p.name)
      self.out.nl()

      self.heading("Mount path: ")
      self.headtext(p.worktree)
      self.out.nl()

      self.heading("Current revision: ")
      self.headtext(p.GetRevisionId())
      self.out.nl()

      currentBranch = p.CurrentBranch
      if currentBranch:
        self.heading('Current branch: ')
        self.headtext(currentBranch)
        self.out.nl()

      self.heading("Manifest revision: ")
      self.headtext(p.revisionExpr)
      self.out.nl()

      localBranches = list(p.GetBranches().keys())
      self.heading("Local Branches: ")
      self.redtext(str(len(localBranches)))
      if localBranches:
        self.text(" [")
        self.text(", ".join(localBranches))
        self.text("]")
      self.out.nl()

      if self.opt.all:
        self.findRemoteLocalDiff(p)

      self.printSeparator()

  def findRemoteLocalDiff(self, project):
    # Fetch all the latest commits.
    if not self.opt.local:
      project.Sync_NetworkHalf(quiet=True, current_branch_only=True)

    branch = self.manifest.manifestProject.config.GetBranch('default').merge
    if branch.startswith(R_HEADS):
      branch = branch[len(R_HEADS):]
    logTarget = R_M + branch

    bareTmp = project.bare_git._bare
    project.bare_git._bare = False
    localCommits = project.bare_git.rev_list(
        '--abbrev=8',
        '--abbrev-commit',
        '--pretty=oneline',
        logTarget + "..",
        '--')

    originCommits = project.bare_git.rev_list(
        '--abbrev=8',
        '--abbrev-commit',
        '--pretty=oneline',
        ".." + logTarget,
        '--')
    project.bare_git._bare = bareTmp

    self.heading("Local Commits: ")
    self.redtext(str(len(localCommits)))
    self.dimtext(" (on current branch)")
    self.out.nl()

    for c in localCommits:
      split = c.split()
      self.sha(split[0] + " ")
      self.text(" ".join(split[1:]))
      self.out.nl()

    self.printSeparator()

    self.heading("Remote Commits: ")
    self.redtext(str(len(originCommits)))
    self.out.nl()

    for c in originCommits:
      split = c.split()
      self.sha(split[0] + " ")
      self.text(" ".join(split[1:]))
      self.out.nl()

  def _printCommitOverview(self, opt, args):
    all_branches = []
    for project in self.GetProjects(args, all_manifests=not opt.this_manifest_only):
      br = [project.GetUploadableBranch(x)
            for x in project.GetBranches()]
      br = [x for x in br if x]
      if self.opt.current_branch:
        br = [x for x in br if x.name == project.CurrentBranch]
      all_branches.extend(br)

    if not all_branches:
      return

    self.out.nl()
    self.heading('Projects Overview')
    project = None

    for branch in all_branches:
      if project != branch.project:
        project = branch.project
        self.out.nl()
        self.headtext(project.RelPath(local=opt.this_manifest_only))
        self.out.nl()

      commits = branch.commits
      date = branch.date
      self.text('%s %-33s (%2d commit%s, %s)' % (
          branch.name == project.CurrentBranch and '*' or ' ',
          branch.name,
          len(commits),
          len(commits) != 1 and 's' or '',
          date))
      self.out.nl()

      for commit in commits:
        split = commit.split()
        self.text('{0:38}{1} '.format('', '-'))
        self.sha(split[0] + " ")
        self.text(" ".join(split[1:]))
        self.out.nl()
