# Copyright (c) 2024 Kent State University CAE Networking Lab

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

import argparse
import sys

class UnknownImageOSError(Exception):
  def __init__ (self, image):
    self._image = image
  def __str__ (self):
    return "Unknown OS for Image '%s'" % (self._image)

class BundleHandler:
  INTEGDIR = "tgen-integ"

  def __init__ (self, slice_node):
    self.slice_node = slice_node
    self.dfilepath = None
    self.use_installer = None
    self._determineOS()

  def deliverPkgBundle (self, bundle_path):
    if "/" in bundle_path:
      self.dfilepath = bundle_path.split("/")[-1]
    else:
      self.dfilepath = bundle_path
    try:
      self.slice_node.upload_file(bundle_path, self.dfilepath)
    except FileNotFoundError as e:
      print("FileNotFoundError: %s" % e)
      print("Is there a file at local path %s?" % (bundle_path)) 
      print("Is the destination filename %s correct?" % (self.dfilepath))
    self.extractBundle()
    if self._checkDir():
      print("Bundle extracted and ready @%s: %s" % 
            (self.slice_node.get_name(), self.slice_node.execute("ls | grep %s" % (self.INTEGDIR), quiet = True)[0]))

  def extractBundle (self):
    self.slice_node.execute("tar xvf %s" % (self.dfilepath), quiet = True)
    if not self._checkDir():
      print("Error: failed to prepare %s @%s to setup project" % 
             (self.INTEGDIR, self.slice_node.get_name()))

  def _checkApt (self):
    out = self.slice_node.execute("which apt", quiet = True)
    if "no apt in" in out[1]:
      return False

  def _determineOS (self):
    image = self.slice_node.get_image()
    if "ubuntu" in image:
      self.use_installer = "apt"
    elif "debian" in image:
      self.use_installer = "apt"
    else:
      raise UnknownImageOSError(image)

  def installdpkg (self, get_log = False):
    if not self.use_installer:
      print("Not implemented")
      return
    elif self.use_installer == "apt":
      self.slice_node.execute("sudo apt-get update", quiet = True)
      self.slice_node.execute("cd ~/%s/dpkg/;sudo dpkg -i *.deb > dpkg.log;sudo apt-get -f -y install > aptinstall.log" % 
           (self.INTEGDIR), quiet = True)
      if get_log:
        logdir_remote = self.slice_node.execute("cd ~/%s/dpkg/;pwd" % (self.INTEGDIR), output_file = True)[0].strip()
        self.slice_node.download_file("dpkg.log", "%s/dpkg.log" % (logdir_remote))
        self.slice_node.download_file("aptinstall.log", "%s/aptinstall.log" % (logdir_remote))
  
  def _setupvenv (self):
    try:
      stdout, stderr = self.slice_node.execute("mkdir env;sudo pip3 install virtualenv;virtualenv -p python3 ~/env/tgen", quiet = True)
    except Exception as e:
      print(f"Exception: {e}")

  def installpypip (self, get_log = False):
    self._setupvenv()
    script_name = "pip3_install.sh"
    script_args = " dpkt==1.9.8 netifaces==0.11.0 numpy==1.24.4 pandas==2.0.3 python-dateutil==2.8.2 pytz==2024.1 scipy==1.10.1 six==1.16.0 tzdata==2024.1 "    
    log_name = "pypipinstalls.log"
    try:
      # assumes pip3 is at its latest
      stdout, stderr = self.slice_node.execute("source ~/env/tgen/bin/activate;pip install --upgrade pip", quiet = True)
      stdout, stderr = self.slice_node.execute("source ~/env/tgen/bin/activate;cd ~/%s/pypip;./%s %s > %s" % (self.INTEGDIR, script_name, script_args, log_name), quiet = True)
    except Exception as e:
      print(f"Exception: {e}")
    if get_log:
      logdir_remote = self.slice_node.execute("cd ~/%s/pypip/;pwd" % (self.INTEGDIR), quiet = True, output_file = True)[0].strip()
      self.slice_node.download_file(log_name, "%s/%s" % (logdir_remote, log_name))

  def _checkDir (self):
    out = self.slice_node.execute("ls", quiet = True)
    return self.INTEGDIR in out[0].strip()

  def _makeTgenIntegDir (self):
    if not self._checkDir():
      outm = self.slice_node.execute("mkdir ~/%s" % (self.INTEGDIR), quiet = True)
    return self._checkDir()


if __name__ == "__main__":
  pass
  # get node details from user slice 
    # (node = slice.get_node('Node1') -- node object)
    # input: fabric node object
  # fabric-copy package to node
  # fabric-exec extract and install package on node
  # verify installation on node
