# Copyright 2008 Google 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 logging

from google.appengine.api import users
from google.appengine.ext import db

from codereview import git_models
from codereview import library
from codereview import models

from change_pb2 import ChangeService
from add_patchset_pb2 import *
from complete_patchset_pb2 import *
from upload_patchset_file_pb2 import *
from submit_change_pb2 import *
from util import *

class ChangeServiceImp(ChangeService, InternalAPI):

  @automatic_retry
  def SubmitChange(self, rpc_controller, req, done):
    rsp = SubmitChangeResponse()

    user = users.User(req.owner)
    branch = db.get(db.Key(req.dest_branch_key))
    if not branch:
      rsp.status_code = SubmitChangeResponse.UNKNOWN_BRANCH
      done(rsp)

    rev = commit_to_revision(branch.project, req.commit)
    if rev.patchset:
      rsp.status_code = SubmitChangeResponse.PATCHSET_EXISTS
      done(rsp)

    subject = u(req.commit.subject)[0:100]

    reviewers = []
    cc = []
    if req.bundle_key:
      rb = git_models.ReceivedBundle.get(req.bundle_key)
      if rb:
        reviewers = [x for x in rb.reviewers if x != user]
        cc = [x for x in rb.cc if x != user]

    def trans():
      change = models.Change(
                 subject = subject,
                 description = u(req.commit.message),
                 owner = user,
                 dest_project = branch.project,
                 dest_branch = branch,
                 n_patchsets = 1)
      if cc:
        change.cc = cc;
      change.put()
      if reviewers:
        (added_review_status, deleted_review_status, new_review_status) = \
            library.update_reviewers(change, [], reviewers)
        for rs in added_review_status:
          rs.put()

      patchset = models.PatchSet(
                   change = change,
                   owner = user,
                   parent = change,
                   revision = rev,
                   id = 1)
      patchset.put()
      return (change, patchset)
    change, patchset = db.run_in_transaction(trans)

    library.send_new_change_emails(change, change.owner, reviewers, cc)

    if rev.link_patchset(patchset):
      rsp.status_code = SubmitChangeResponse.CREATED
      rsp.change_id = change.key().id()
      rsp.patchset_id = patchset.id
      rsp.patchset_key = str(patchset.key())
    else:
      db.delete([change, patchset])
      rsp.status_code = SubmitChangeResponse.PATCHSET_EXISTS
    done(rsp)

  @automatic_retry
  def AddPatchSet(self, rpc_controller, req, done):
    rsp = AddPatchSetResponse()

    user = users.User(req.owner)
    branch = db.get(db.Key(req.dest_branch_key))
    if not branch:
      rsp.status_code = AddPatchSetResponse.UNKNOWN_BRANCH
      done(rsp)

    rev = commit_to_revision(branch.project, req.commit)
    if rev.patchset:
      rsp.status_code = AddPatchSetResponse.PATCHSET_EXISTS
      done(rsp)

    subject = u(req.commit.subject)[0:100]

    def trans():
      change = models.Change.get_by_id(req.change_id)
      if not change:
        return None

      change.subject = subject
      change.description = u(req.commit.message)
      change.n_patchsets += 1
      id = change.n_patchsets
      change.put()

      patchset = models.PatchSet(
                   change = change,
                   owner = user,
                   parent = change,
                   revision = rev,
                   id = id)
      patchset.put()
      return patchset
    patchset = db.run_in_transaction(trans)
    if not patchset:
      rsp.status_code = AddPatchSetResponse.UNKNOWN_CHANGE
      done(rsp)

    if rev.link_patchset(patchset):
      rsp.status_code = AddPatchSetResponse.CREATED
      rsp.patchset_id = patchset.id
      rsp.patchset_key = str(patchset.key())
    else:
      db.delete(patchset)
      rsp.status_code = AddPatchSetResponse.PATCHSET_EXISTS
    done(rsp)

  @automatic_retry
  def UploadPatchsetFile(self, rpc_controller, req, done):
    rsp = UploadPatchsetFileResponse()

    patchset = db.get(db.Key(req.patchset_key))
    if not patchset:
      rsp.status_code = UploadPatchsetFileResponse.UNKNOWN_PATCHSET
      done(rsp)
      return

    if patchset.complete or patchset.change.closed:
      rsp.status_code = UploadPatchsetFileResponse.CLOSED
      done(rsp)
      return

    if UploadPatchsetFileRequest.ADD == req.status:
      status = 'A'
    elif UploadPatchsetFileRequest.MODIFY == req.status:
      status = 'M'
    elif UploadPatchsetFileRequest.DELETE == req.status:
      status = 'D'
    else:
      status = '?'

    try:
      if req.base_id:
        old_data = models.DeltaContent.create_content(
                     id = req.base_id,
                     text_z = req.base_z)
        new_data = models.DeltaContent.create_content(
                     id = req.final_id,
                     text_z = req.patch_z,
                     base = old_data)
        if new_data.text_z == req.patch_z:
          diff_data = new_data
        else:
          diff_data = models.DeltaContent.create_patch(
                        id = req.patch_id,
                        text_z = req.patch_z)
      else:
        old_data = None
        new_data = None
        diff_data = models.DeltaContent.create_patch(
                      id = req.patch_id,
                      text_z = req.patch_z)
    except models.DeltaPatchingException:
      logging.error("Patch error on change %s, patch set %s, file %s"
        % (patchset.change.key().id(),
           str(patchset.id),
           u(req.file_name))
      )
      rsp.status_code = UploadPatchsetFileResponse.PATCHING_ERROR
      done(rsp)
      return

    file_name = u(req.file_name)
    other_versions = []
    other_patches = []

    if patchset.id > 1:
      for ps in models.gql(models.PatchSet,
                           'WHERE change = :1'
                           ' ORDER BY id',
                           patchset.change).fetch(1000):
        if ps.id == patchset.id:
          continue

        prior = models.Patch.get_patch_by_filename(ps, file_name)
        if prior and not prior.patch_equals(diff_data):
          other_versions.append('%d %d %s'
                                % (ps.key().id(), ps.id, prior.id))
          other_patches.append(prior)

    patch = models.Patch.get_or_insert_patch(
              patchset = patchset,
              filename = file_name,
              status = status,
              multi_way_diff = req.multi_way_diff,
              n_comments = 0,
              old_data = old_data,
              new_data = new_data,
              diff_data = diff_data,
              other_versions = other_versions)

    my_ovstr = '%d %d %s' % (patchset.key().id(),
                             patchset.id,
                             patch.id)
    def trans():
      for prior in other_patches:
        p = db.get(prior.key())
        p.other_versions.append(my_ovstr)
        p.put()
    db.run_in_transaction(trans)

    if old_data:
      models.CachedDeltaContent.get(old_data.key())
      models.CachedDeltaContent.get(new_data.key())
      if diff_data != new_data:
        models.CachedDeltaContent.get(diff_data.key())
    else:
      models.CachedDeltaContent.get(diff_data.key())

    rsp.status_code = UploadPatchsetFileResponse.CREATED
    done(rsp)

  @automatic_retry
  def CompletePatchset(serlf, rpc_controller, req, done):
    rsp = CompletePatchsetResponse()

    patchset = db.get(db.Key(req.patchset_key))
    if not patchset.complete:
      patchset.complete = True
      patchset.put()

      if len(req.compressed_filenames) > 0:
        models.PatchSetFilenames.store_compressed(
          patchset,
          req.compressed_filenames)
    done(rsp)
