# ==================================================================================================
# Copyright 2013 Twitter, Inc.
# --------------------------------------------------------------------------------------------------
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this work except in compliance with the License.
# You may obtain a copy of the License in the LICENSE file, or 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 print_function

import os
import shutil
import tempfile
import textwrap

from twitter.common.dirutil.chroot import RelativeChroot
from twitter.pants.python.sdist_builder import SdistBuilder


class CodeGenerator(object):
  class Error(Exception): pass
  class CodeGenerationException(Error): pass

  def __init__(self, target, root_dir, config, target_suffix=None):
    self.target = target
    self.config = config
    self.suffix = target_suffix or ''
    self.root = root_dir
    distdir = self.config.getdefault('pants_distdir')
    self.chroot = RelativeChroot(root_dir, distdir, target.name)
    codegen_root = tempfile.mkdtemp(dir=self.chroot.path(), prefix='codegen.')
    self.codegen_root = os.path.relpath(codegen_root, self.chroot.path())
    self.created_packages = set()
    self.created_namespace_packages = set()

  def __del__(self):
    self.cleanup()

  def cleanup(self):
    shutil.rmtree(self.chroot.path())

  @staticmethod
  def path_to_module(path):
    return path.replace(os.path.sep, '.')

  def package_name(self):
    return '%s%s' % (self.target.id, self.suffix)

  def requirement_string(self):
    return '%s==0.0.0' % self.package_name()

  @property
  def package_dir(self):
    """Return the code generation root."""
    return "."

  def generate(self):
    """Generate code for this target, updating the sets .created_packages and
       .created_namespace_packages."""
    raise NotImplementedError

  def dump_setup_py(self):
    boilerplate = textwrap.dedent("""
      from setuptools import setup

      setup(name        = "%(package_name)s",
            version     = "0.0.0",
            description = "autogenerated code for %(target_name)s",
            package_dir = { "": %(package_dir)r },
            packages    = %(packages)s,
            namespace_packages = %(namespace_packages)s)
    """)
    boilerplate = boilerplate % {
      'target_name': self.target.id,
      'package_name': self.package_name(),
      'package_dir': self.package_dir,
      'target_name': self.target.name,
      'packages': repr(self.created_packages),
      'namespace_packages': repr(list(self.created_namespace_packages))
    }
    self.chroot.write(boilerplate.encode('utf8'), os.path.join(self.codegen_root, 'setup.py'))
    self.chroot.write("include *.py".encode('utf8'), os.path.join(self.codegen_root, 'MANIFEST.in'))

  @property
  def sdist_root(self):
    return os.path.join(self.chroot.path(), self.codegen_root)

  @property
  def package_root(self):
    return os.path.join(self.sdist_root, self.package_dir)

  def build(self, interpreter=None):
    self.generate()
    self.dump_setup_py()
    return SdistBuilder.build(self.sdist_root, self.target, interpreter=interpreter)
