text: #!/usr/bin/python
  # -*- coding: utf-8 -*-
  
  __copyright__ = """
  
  MIT License
  
  Copyright (c) 2021 Samapriya Roy
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
  
  
  """
  __license__ = "MIT License"
  
  import requests
  import pkg_resources
  import json
  import getpass
  import sys
  import geojson
  import progressbar
  import argparse
  import time
  import base64
  import os
  import webbrowser
  from area import area
  from os.path import expanduser
  from bs4 import BeautifulSoup
  
  
  class Solution:
      def compareVersion(self, version1, version2):
          versions1 = [int(v) for v in version1.split(".")]
          versions2 = [int(v) for v in version2.split(".")]
          for i in range(max(len(versions1), len(versions2))):
              v1 = versions1[i] if i < len(versions1) else 0
              v2 = versions2[i] if i < len(versions2) else 0
              if v1 > v2:
                  return 1
              elif v1 < v2:
                  return -1
          return 0
  
  
  ob1 = Solution()
  
  # Get package version
  def pycoral_version():
      url = "https://pypi.org/project/pycoral/"
      source = requests.get(url)
      html_content = source.text
      soup = BeautifulSoup(html_content, "html.parser")
      company = soup.find("h1")
      vcheck = ob1.compareVersion(
          company.string.strip().split(" ")[-1],
          pkg_resources.get_distribution("pycoral").version,
      )
      if vcheck == 1:
          print(
              "\n"
              + "========================================================================="
          )
          print(
              "Current version of pycoral is {} upgrade to lastest version: {}".format(
                  pkg_resources.get_distribution("pycoral").version,
                  company.string.strip().split(" ")[-1],
              )
          )
          print(
              "========================================================================="
          )
      elif vcheck == -1:
          print(
              "\n"
              + "========================================================================="
          )
          print(
              "Possibly running staging code {} compared to pypi release {}".format(
                  pkg_resources.get_distribution("pycoral").version,
                  company.string.strip().split(" ")[-1],
              )
          )
          print(
              "========================================================================="
          )
  
  
  pycoral_version()
  
  # Go to the readMe
  def readme():
      try:
          a = webbrowser.open("https://samapriya.github.io/pycoral/", new=2)
          if a == False:
              print("Your setup does not have a monitor to display the webpage")
              print(" Go to {}".format("https://samapriya.github.io/pycoral/"))
      except Exception as e:
          print(e)
  
  
  def read_from_parser(args):
      readme()
  
  
  # set credentials
  def auth():
      home = expanduser("~/coral.json")
      usr = input("Enter email: ")
      pwd = getpass.getpass("Enter password: ")
      data = {"email": usr, "password": pwd}
      with open(home, "w") as outfile:
          json.dump(data, outfile)
  
  
  # auth()
  def auth_from_parser(args):
      auth()
  
  
  def tokenize():
      try:
          home = expanduser("~/coral.json")
          with open(home) as json_file:
              data = json.load(json_file)
              if not data.get("email"):
                  email = input("Enter username: ")
              else:
                  email = data.get("email")
              if not data.get("password"):
                  password = getpass.getpass("Enter password: ")
              else:
                  password = data.get("password")
      except Exception as e:
          print(e)
      headers = {
          "authority": "allencoralatlas.org",
          "sec-ch-ua": '" Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"',
          "sec-ch-ua-mobile": "?0",
          "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
          "content-type": "application/x-www-form-urlencoded",
          "accept": "*/*",
          "origin": "https://allencoralatlas.org",
          "sec-fetch-site": "same-origin",
          "sec-fetch-mode": "cors",
          "sec-fetch-dest": "empty",
          "accept-language": "en-US,en;q=0.9",
      }
  
      response = requests.post(
          "https://allencoralatlas.org/auth/login", headers=headers, data=json.dumps(data)
      )
      if response.status_code == 200:
          return response.json()["access_token"]
      else:
          print(
              "Authentication failed with response code {}".format(response.status_code)
          )
  
  
  # List or find system polygons and user polygons
  def poly_list(name):
      bearer = tokenize()
      headers = {
          "authority": "allencoralatlas.org",
          "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
          "authorization": "Bearer {}".format(bearer),
      }
      response = requests.get(
          "https://allencoralatlas.org/mapping/aois?geometries=false", headers=headers
      )
      if response.status_code == 200:
          for things in response.json()["data"]:
              if name is None:
                  if not things["owner"] is None and things["is_group"] == False:
                      print(f"User Poly - {things['name']} : {things['id']}")
                  elif things["is_group"] == False:
                      print(f"Default Poly - {things['name']} : {things['id']}")
              elif name is not None:
                  if things["name"].strip().lower() == name.strip().lower():
                      print(f"Matchind ID : {things['id']}")
                      print("")
                      return things["id"]
      else:
          print(
              f"Failed to fetch default or user areas with response : {response.status_code}"
          )
  
  
  def poly_list_from_parser(args):
      poly_list(name=args.name)
  
  
  def getarea(geom):
      obj = {"type": "Polygon", "coordinates": []}
      obj["coordinates"] = geom
      poly_area = area(obj)
      return poly_area / 1000000
  
  
  def poly_create(filepath, name):
      if name is not None:
          if name.isdigit():
              id = str(name)
          else:
              id = poly_list(name=str(name))
      else:
          sys.exit("Pass valid geometry name or ID")
      if id is None:
          print(f"Polygon name does not exist: Creating {name}")
      else:
          sys.exit(f"Existing polygon name {name} found: Try a different name or delete")
      bearer = tokenize()
      headers = {
          "authority": "allencoralatlas.org",
          "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
          "authorization": "Bearer {}".format(bearer),
      }
      with open(filepath) as f:
          gj = geojson.load(f)
      features = gj["features"][0]
      area_value = getarea(features["geometry"]["coordinates"])
      print(f"Total area in sqkm {round(area_value,2)}")
      data = {
          "name": name,
          "unsaved": False,
          "owner": "local",
          "local": True,
          "geom": {"type": "Polygon", "coordinates": []},
      }
      data["geom"]["coordinates"] = features["geometry"]["coordinates"]
      response = requests.post(
          "https://allencoralatlas.org/mapping/aois",
          headers=headers,
          data=json.dumps(data),
      )
      if response.status_code == 201:
          print(
              f"Created {response.json()['data']['name']} with ID: {response.json()['data']['id']}"
          )
          return response.json()["data"]["id"]
      else:
          print(
              f"Create failed with response {response.status_code} and error message {response.string}"
          )
  
  
  def poly_create_from_parser(args):
      poly_create(name=args.name, filepath=args.geometry)
  
  
  def poly_delete(id):
      if id is not None:
          if id.isdigit():
              id = str(id)
          else:
              id = poly_list(name=str(id))
      else:
          sys.exit("Pass valid geometry name or ID")
      bearer = tokenize()
      headers = {
          "authority": "allencoralatlas.org",
          "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
          "authorization": "Bearer {}".format(bearer),
      }
      response = requests.delete(
          f"https://allencoralatlas.org/mapping/aois/{id}", headers=headers
      )
      if response.status_code == 200:
          print(f"Deleted {id} successfully")
      else:
          print(f"No results for name or id {id}: returned {response.status_code}")
  
  
  def poly_delete_from_parser(args):
      poly_delete(id=args.aoi)
  
  
  def poly_stat(id, filepath):
      bearer = tokenize()
      headers = {
          "authority": "allencoralatlas.org",
          "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
          "authorization": "Bearer {}".format(bearer),
      }
      if id is not None:
          if id.isdigit():
              id = str(id)
          else:
              id = poly_list(name=str(id))
          response = requests.get(
              f"https://allencoralatlas.org/mapping/aois/{id}/stats", headers=headers
          )
      elif id is None and filepath is not None:
          with open(filepath) as f:
              gj = geojson.load(f)
          features = gj["features"][0]
          area_value = getarea(features["geometry"]["coordinates"])
          if int(area_value) < 100:
              data = {"geom": {"type": "Polygon", "coordinates": []}}
              data["geom"]["coordinates"] = features["geometry"]["coordinates"]
              response = requests.post(
                  "https://allencoralatlas.org/mapping/aois/stats",
                  headers=headers,
                  data=json.dumps(data),
              )
          else:
              print("AOI area exceeds 100 sqkm: Creating Polygon to run stats")
              current_timestamp = str(time.time())
              message_bytes = current_timestamp.encode("ascii")
              base64_bytes = base64.b64encode(message_bytes)
              name = base64_bytes.decode("ascii")
              id = poly_create(filepath, name)
              response = requests.get(
                  f"https://allencoralatlas.org/mapping/aois/{id}/stats", headers=headers
              )
              while response.status_code != 200:
                  time.sleep(5)
                  response = requests.get(
                      f"https://allencoralatlas.org/mapping/aois/{id}/stats",
                      headers=headers,
                  )
      else:
          sys.exit("Pass valid geometry, name or ID")
      if response.status_code == 200:
          if float(response.json()["data"]["stats"]["mapped_sqkm"]) > 0.0:
              print(json.dumps(response.json()["data"], indent=2))
          else:
              print("No mapped area for the AOI")
      else:
          print(f"No results for name or id {id}: returned {response.status_code}")
  
  
  def poly_stat_from_parser(args):
      poly_stat(id=args.aoi, filepath=args.geometry)
  
  
  def downloader(url, local_path):
      response = requests.request("HEAD", url)
      filename = url.split("/")[-1]
      local_path = os.path.join(local_path, filename)
      print("Waiting for zip file to complete ...")
      try:
          while response.status_code != 200:
              bar = progressbar.ProgressBar()
              for _ in bar(range(60)):
                  time.sleep(1)
              response = requests.request("HEAD", url)
          if not os.path.exists(local_path) and response.status_code == 200:
              print(f"Downloading to :{local_path}")
              response = requests.get(url)
              f = open(local_path, "wb")
              for chunk in response.iter_content(chunk_size=512 * 1024):
                  if chunk:
                      f.write(chunk)
              f.close()
          elif response.status_code == 429:
              raise Exception("rate limit error")
          else:
              if int(response.status_code) != 200:
                  print(
                      f"Encountered error with code: {result.status_code} for {os.path.split(items['name'])[-1]}"
                  )
              elif int(response.status_code) == 200:
                  print(f"File already exists SKIPPING: {os.path.split(local_path)[-1]}")
      except Exception as e:
          print(e)
      except KeyboardInterrupt:
          sys.exit("\n" + "Exited by user")
  
  
  def poly_download(id, local_path, format):
      if id is not None:
          if id.isdigit():
              id = str(id)
          else:
              id = poly_list(name=str(id))
      else:
          sys.exit("Pass valid geometry name or ID")
      bearer = tokenize()
      headers = {
          "authority": "allencoralatlas.org",
          "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36",
          "authorization": "Bearer {}".format(bearer),
      }
      aoi_check = requests.get(
          f"https://allencoralatlas.org/mapping/aois/{id}", headers=headers
      )
      if aoi_check.status_code == 200 and aoi_check.json()["data"]["owner"] is None:
          print(
              f"This is a system polygon checking for a user copy of {aoi_check.json()['data']['name']}"
          )
          user_poly = f"{aoi_check.json()['data']['name'].lower().replace(' ', '_')}_user"
          id = poly_list(name=str(user_poly))
          print("""
              User copies of system polygon can take a long time to prepare for download
              Once order is placed use Ctrl+C to terminate and wait for the download email to be sent
              """)
          if id is not None:
              print(f"Existing polygon name {user_poly} found")
          else:
              print(f"Polygon name does not exist: Creating {user_poly}")
              data = {
                  "name": user_poly,
                  "unsaved": False,
                  "owner": "local",
                  "local": True,
                  "geom": {
                      "type": "MultiPolygon",
                      "coordinates": aoi_check.json()["data"]["geom"]["coordinates"],
                  },
              }
              response = requests.post(
                  "https://allencoralatlas.org/mapping/aois",
                  headers=headers,
                  data=json.dumps(data),
              )
              if response.status_code == 201:
                  print(
                      f"Created {response.json()['data']['name']} with ID: {response.json()['data']['id']}"
                  )
                  id = response.json()["data"]["id"]
              else:
                  print(
                      f"Create failed with response {response.status_code} and error message {response.text}"
                  )
          # print(id)
      data = {"datasets": "empty"}
      product_dict = {}
      response = requests.get(
          f"https://allencoralatlas.org/mapping/aois/{id}/products", headers=headers
      )
      for products in response.json()["data"]:
          if products["allow_downloads"] == True:
              if format in products["options"]["valid_formats"]:
                  product_dict[products["uuid"]] = format
              else:
                  product_dict[products["uuid"]] = products["options"]["default_format"]
      data["datasets"] = product_dict
      response = requests.post(
          f"https://allencoralatlas.org/download/aois/{id}",
          headers=headers,
          data=json.dumps(data),
      )
  
      if response.status_code == 200:
          print(f'Submited {response.json()["data"]["name"]} for download')
          downloader(response.json()["data"]["url"], local_path)
      elif response.status_code == 202:
          print(f'Submited {response.json()["data"]["name"]} for download')
          downloader(response.json()["data"]["url"], local_path)
      else:
          print(f"No results for name or id {id}: returned {response.status_code}")
  
  
  def poly_download_from_parser(args):
      poly_download(id=args.aoi, local_path=args.local, format=args.format)
  
  
  def main(args=None):
      parser = argparse.ArgumentParser(description="Simple CLI for Allen Coral Atlas")
      subparsers = parser.add_subparsers()
  
      parser_read = subparsers.add_parser(
          "readme", help="Go to the web based pycoral readme page"
      )
      parser_read.set_defaults(func=read_from_parser)
  
      parser_auth = subparsers.add_parser("auth", help="Saves your username and password")
      parser_auth.set_defaults(func=auth_from_parser)
  
      parser_poly_list = subparsers.add_parser(
          "aoi-find", help="Find AOI name and ID or list all"
      )
      optional_named = parser_poly_list.add_argument_group("Optional named arguments")
      optional_named.add_argument("--name", help="Pass area name", default=None)
      parser_poly_list.set_defaults(func=poly_list_from_parser)
  
      parser_poly_create = subparsers.add_parser(
          "aoi-create", help="Use a GeoJSON geometry file to create My Area AOI"
      )
      required_named = parser_poly_create.add_argument_group("Required named arguments.")
      required_named.add_argument("--name", help="AOI name", required=True)
      required_named.add_argument(
          "--geometry", help="Full path to geometry.geojson file", required=True
      )
      parser_poly_create.set_defaults(func=poly_create_from_parser)
  
      parser_poly_stat = subparsers.add_parser(
          "aoi-stat",
          help="Print summary statistics for AOI using geoemtry file, name or ID",
      )
      optional_named = parser_poly_stat.add_argument_group("Optional named arguments")
      optional_named.add_argument("--aoi", help="AOI name or ID", default=None)
      optional_named.add_argument(
          "--geometry", help="Full path to geometry.geojson file", default=None
      )
      parser_poly_stat.set_defaults(func=poly_stat_from_parser)
  
      parser_poly_delete = subparsers.add_parser(
          "aoi-delete", help="Delete AOI from My Areas list"
      )
      required_named = parser_poly_delete.add_argument_group("Required named arguments.")
      required_named.add_argument("--aoi", help="AOI name or ID", required=True)
      parser_poly_delete.set_defaults(func=poly_delete_from_parser)
  
      parser_poly_download = subparsers.add_parser(
          "aoi-download", help="Download files using name or ID"
      )
      required_named = parser_poly_download.add_argument_group(
          "Required named arguments."
      )
      required_named.add_argument("--aoi", help="AOI name or ID", required=True)
      required_named.add_argument(
          "--local", help="Full path to folder to download files", required=True
      )
      optional_named = parser_poly_download.add_argument_group("Optional named arguments")
      optional_named.add_argument(
          "--format", help="Format types 'geojson', 'kml', 'shp', 'gpkg'", default=None
      )
      parser_poly_download.set_defaults(func=poly_download_from_parser)
  
      args = parser.parse_args()
  
      try:
          func = args.func
      except AttributeError:
          parser.error("too few arguments")
      func(args)
  
  
  if __name__ == "__main__":
      main()
  