//==========================================
// Helper Functions ------------------------
//==========================================

getMimeTypFromFileName = function (flName)
{
  var fileNameArray = flName.toLowerCase().split(".");
  var fileName = fileNameArray[fileNameArray.length - 2];
  var fileExtension = fileNameArray[fileNameArray.length - 1];

  switch (fileExtension)
  {
    case "wpm": return("text/html");
    case "jpg":
    case "jpeg":
      return("image/jpeg");
    case "png": return("image/png");
    case "tif":
    case "tiff":
      return("image/tiff");
    case "bmp": return("image/bmp");
    case "svg": return("image/svg+xml");
    case "gif": return("image/giv");
    case "pdf": return("application/pdf");
    default: return("application/" + fileExtension);
  }
};//getMimeTypFromFileName

canBeUsed = function (selector, isUsable)
{
  let uiEntity = null;
  if (typeof selector === 'string')
    uiEntity = document.getElementById(selector);
  else
    uiEntity = selector;

  if(uiEntity != null)
  {
    if(isUsable == false)
    {
      uiEntity.style.filter = "blur(2px)";
      uiEntity.disabled = true;
    }
    else
    {
      uiEntity.style.filter = "blur(0px)";
      uiEntity.disabled = false;
    }
  }
};//canBeUsed

setDisplayStyle = function (selector, dStyle)
{
  var uiEntities = null;

  if(selector[0]=='#')
  {
    uiEntities = document.querySelectorAll(selector);
    for (i=0; i<uiEntities.length; i++)
    {
      uiEntities[i].style.display = dStyle;
    }
  }
  else
  {
    uiEntities = document.getElementById(selector);
    if(uiEntities != null) uiEntities.style.display = dStyle;
  }
};//setDisplayStyle

function isSameOrigin(url)
{
  var loc = window.location;
  var a = document.createElement('a');

  a.href = url;

  return a.hostname == loc.hostname &&
         a.port == loc.port &&
         a.protocol == loc.protocol;
}
//==========================================
// Document classes ------------------------
//==========================================
/*
Data Structure:
Poi3dStorageConnector
  this.categories = Array of Poi3dStorageCategory's
    _documentCollections = Array of Poi3dStorageDocumentCollection's
      _documents = Array of Poi3dStorageDocument's
        _fileAttachments = Array of Poi3dStorageFileAttachment's
        _attributes = Array of Poi3dStorageAttribute's
*/

var Poi3dStorageCategory = function()
{
  var _title = "";
  var _id = "";
  var _loaded = false;
  var _documentCollections = new Array();

  this.getId = function (){return _id;};
  this.setId = function (newId){_id = newId;};
  this.getTitle = function (){return _title;};
  this.setTitle = function (newTitle){_title = newTitle;};
  this.getLoadState = function (){return _loaded;};
  this.setLoadState = function (newLoadState){_loaded = newLoadState;};
  this.getDocumentCollections = function(){ return _documentCollections};

  this.findStorageDocument = function(docId)
  {
    let foundDoc = null;

    for(let i=0; i<_documentCollections.length; i++)
    {
      foundDoc = _documentCollections[i].findStorageDocument(docId);
      if(foundDoc != null) return(foundDoc);
    }
    return null;
  };

};//Poi3dStorageDocumentCollection

var Poi3dStorageDocumentCollection = function(categoryObject)
{
  var _title = "";
  var _id = "";
  var _documents = new Array();
  var _category = categoryObject;
  var _loaded = false;

  this.getCategory = function (){return _category;};
  this.getId = function (){return _id;};
  this.setId = function (newId){_id = newId;};
  this.getTitle = function (){return _title;};
  this.setTitle = function (newTitle){_title = newTitle;};
  this.getLoadState = function (){return _loaded;};
  this.setLoadState = function (newLoadState){_loaded = newLoadState;};
  this.getDocuments = function(){return _documents;};

  this.findStorageDocument = function(docId)
  {
    let foundDoc = null;
    foundDoc = _documents.find((storeDoc) => storeDoc.getDocId() === docId);

    if(foundDoc != null)
      return(foundDoc);
    else
      return null;
  };

};//Poi3dStorageDocumentCollection

var Poi3dStorageDocument = function(collectionObject)
{
  var _attributes = new Array();
  var _description = "";
  var _docData = null;
  var _docId = "";
  var _docType = "";
  var _docTypeOrg = "";
  var _fileAttachments = new Array();
  var _fileName = "";
  var _isFromDb = false;
  var _previewUrl = "";
  var _thumbnailUrl = "";
  var _title = "";
  var _mimeType = "";
  var _docFileNameNoExt = "";
  var _collection = collectionObject;

  this.getCollection = function (){return _collection;};
  this.getAttributes = function (){return _attributes;};
  this.setAttributes = function (newAttributeArray){_attributes = newAttributeArray;};
  this.getDbFlag = function (){return _isFromDb};
  this.setDbFlag = function (newDbFlag){_isFromDb = newDbFlag;};
  this.getDescription = function (){return _description;};
  this.setDescription = function (newDescription){_description = newDescription;};
  this.getDocData = function (){return _docData;};
  this.setDocData = function (newDocData){_docData = newDocData;};
  this.getDocId = function (){return _docId;};
  this.setDocId = function (newDocId){_docId = newDocId;};
  this.getDocType = function (){return _docType;};
  this.setDocType = function (newDocType){_docType = newDocType;};
  this.getDocTypeOrg = function (){return _docTypeOrg;};
  this.setDocTypeOrg = function (newDocTypeOrg){_docTypeOrg = newDocTypeOrg;};
  this.getFileAttachments = function (){return _fileAttachments;};
  this.getFileName = function (){return _fileName;};
  this.setFileName = function (newFileName)
  {
    _fileName = newFileName;

    let docNameParts = newFileName.split(".");
    let docExt = docNameParts[docNameParts.length-1];
    _docType = docExt.toLowerCase();
    _docFileNameNoExt = newFileName.replace("."+docExt, "")
    _mimeType = getMimeTypFromFileName(newFileName);
  };
  this.getFileNameNoExt = function (){return _docFileNameNoExt;};
  this.getPreviewUrl = function (){return _previewUrl;};
  this.setPreviewUrl = function (newPreviewUrl){_previewUrl = newPreviewUrl;};
  this.getThumbnailUrl = function (){return _thumbnailUrl;};
  this.setThumbnailUrl = function (newThumbnailUrl){_thumbnailUrl = newThumbnailUrl;};
  this.getTitle = function (){return _title;};
  this.setTitle = function (newTitle){_title = newTitle;};
  this.getMimeType = function (){return _mimeType;};
  this.setMimeType = function (newMimeType)
  {
    _mimeType = newMimeType;

    let mimeTypeParts = newMimeType.split("/");
    _docType = mimeTypeParts[mimeTypeParts.length-1].toLowerCase();
    if(_docType.includes("svg")) _docType="svg";
  };

};//Poi3dStorageDocument

var Poi3dStorageAttribute = function()
{
  var _daKey = "";
  var _daVal = "";
  var _daTtl = "";

  this.getTitle = function ()
  {
    if(_daTtl.length == 0)
      return _daKey;
    else
      return _daTtl;
  };
  this.setTitle = function (newTitle){_daTtl = newTitle;};
  this.getValue = function (){return _daVal;};
  this.setValue = function (newValue){_daVal = newValue;};
  this.getKey = function (){return _daKey;};
  this.setKey = function (newKey){_daKey = newKey;};
};//Poi3dStorageAttribute

var Poi3dStorageFileAttachment = function()
{
  var _title = "";
  var _description = "";
  var _id = "";
  var _fileName = "";
  var _mimeType = "";

  this.getTitle = function (){return _title;};
  this.setTitle = function (newTitle){_title = newTitle;};
  this.getDescription = function (){return _description;};
  this.setDescription = function (newDesc){_description = newDesc;};
  this.getId = function (){return _id;};
  this.setId = function (newId){_id = newId;};
  this.getMimeType = function (){return _mimeType;};
  this.setMimeType = function (newMimeType){_mimeType = newMimeType;};
  this.getFileName = function (){return _fileName;};
  this.setFileName = function (newFileName)
  {
    _fileName = newFileName;
    _mimeType = getMimeTypFromFileName(newFileName);
  };

};//Poi3dStorageFileAttachment

//==========================================
// Connector Base class --------------------
//==========================================
var Poi3dStorageConnector = function()
{
  var _viewableFormats = ["wpm","jpg","jpeg","bmp","gif","svg","png","pdf","tif","tiff"];

  this.configuration = {"context":"base","storageAddress":"","storageSubAddress":"","storageLang":"","poi3dPortalAddress":"./Poi3dViewer.html","userName":""};
  this.isUserLoggedIn = false;
  this.categories = new Array();
  this.documentCollectionLoadedCb = null;
  this.updateStateCb = null;
  this.categoryListLoadedCb = null;
  this.categoriesLoadedCb = null;
  this.fileAttachmentsLoadedCb = null;
  this.attributesLoadedCb = null;
  this.categorySelectedCb = null;
  this.libraries = new Array();

  var _cmiWindow = null;

  this.setCmiWindow = function(newCmiWindow ){_cmiWindow  = newCmiWindow ;};

  this.getCategories = function (){return this.categories;};

  this.isViewableFormat = function(type)
  {
    if(type == undefined) return false;

    let foundType = null;
    foundType = _viewableFormats.find((format) => format === type);

    if(foundType != null)
      return true;
    else
      return false;
  };

  this.registerCallback = function(context, func)
  {
    switch (context)
    {
      case "categoriesLoaded":
        this.categoriesLoadedCb = func;
        break;
      case "categoryListLoaded":
        this.categoryListLoadedCb = func;
        break;
      case "categorySelected":
        this.categorySelectedCb = func;
        break;
      case "documentCollectionLoaded":
        this.documentCollectionLoadedCb = func;
        break;
      case "fileAttachmentsLoaded":
        this.fileAttachmentsLoadedCb = func;
        break;
      case "attributesLoaded":
        this.attributesLoadedCb = func;
        break;
      case "updateState":
        this.updateStateCb = func;
        break;
    }
  };//Poi3dStorageConnector.registerCallback

  this.findStorageDocument = function(docId)
  {
    let foundDoc = null;

    for(let i=0; i< this.categories.length; i++)
    {
      foundDoc = this.categories[i].findStorageDocument(docId);
      if(foundDoc != null) return(foundDoc);
    }
    return null;
  };

  //Interface methods
  this.init = function (){};
  this.login = function (userName,userPwd){};
  this.logoff = function (){};
  this.loadCategory = function (categoryObject){};
  this.loadDocumentCollection = function (documentCollectionObject){};
  this.loadPreview = async function (documentObject){};
  this.downloadFileAttachment = function (fileAttachmentObject){};
  //Cross-Domain access https://adiachituve.medium.com/how-to-achieve-cross-domain-localstorage-790a657ec36f
  this.openDocumentInPortal = function (documentObject)
  {
    let currLoc = location.href.replace(/\/[^\/]+?\.[^\/]+?$/, '/');
    if(isSameOrigin(this.configuration.poi3dPortalAddress))
      window.open(this.configuration.poi3dPortalAddress + "?dbId="+documentObject.getDocId(),"_blank");
    else
      window.open(this.configuration.poi3dPortalAddress + "?dbId="+documentObject.getDocId() + "&dbAccess=" + currLoc  ,"_blank");
  };//Poi3dCatalogConnector.openDocumentInPortal (base function overwrite)

  //browser storage functions
  this.saveConfigurationToBrowserStorage = function ()
  {
    getConnectionInfo();//!! call to ui method
    let configString = JSON.stringify(this.configuration);

    if(this.updateStateCb != null)
      this.updateStateCb("Saved to Browser Storage");

    return (localStorage.setItem(this.configuration.context,configString));
  };

  this.readConfigurationFromBrowserStorage = function ()
  {
    let configString = localStorage.getItem(this.configuration.context);
    if(configString)
    {
      this.configuration = JSON.parse(configString);
      restoreConnectionInfo();//!! call to ui method
    }
  };

  this.clearBrowserDb = function()
  {
    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
    window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;

    var clearRequest = window.indexedDB.open("Poi3dBrowserStorageDb");
    clearRequest.onsuccess = function(event)
    {
      let browserStorage = clearRequest.result;
      let documentStore = browserStorage.transaction("Documents", "readwrite").objectStore("Documents");
      documentStore.clear();
    };

    clearRequest.onupgradeneeded = function(event)
    {
      let browserStorage = event.target.result;
      var modelObjectStore = browserStorage.createObjectStore("Documents", { keyPath: "docId" });
    };//docRequest.onupgradeneeded

  };//Poi3dStorageConnector.clearBrowserDb

  this.saveDocumentToBrowserDb = async function(poi3dStorageDocument)
  {
    let dbPromise = new Promise(function(resolve)
    {
      window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
      window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
      window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;

      var docRequest = window.indexedDB.open("Poi3dBrowserStorageDb");

      docRequest.onerror = function(event)
      {
        resolve(-1);
      };//docRequest.onerror

      docRequest.onsuccess = function(event)
      {
        let browserStorage = docRequest.result;
        let docNameParts = poi3dStorageDocument.getFileName().split(".");
        let docType = poi3dStorageDocument.getDocType();
        let docFname = poi3dStorageDocument.getFileName();

        if(docType == "zip")
        {
          docType = "wpm";
          docFname = docFname.replace(".zip", ".wpm")
        }

        let documentStore = browserStorage.transaction("Documents", "readwrite").objectStore("Documents");
        documentStore.count().onsuccess = function(event)
        {
          let storageDocAttribs = poi3dStorageDocument.getAttributes();

          poi3dAtributes = new Array();
          for(let i=0;i<storageDocAttribs.length;i++)
          {
            poi3dAtributes.push({"daKey":storageDocAttribs[i].getKey(),"daTtl":storageDocAttribs[i].getTitle(),"daVal":storageDocAttribs[i].getValue()});
          }
          let attributes = [{"daTplNm":"","daIsTop":true,"daProps":poi3dAtributes}];
          let docData = poi3dStorageDocument.getDocData();

          let documentToSave = {"docId":poi3dStorageDocument.getDocId(),"docType":docType,"docFname":docFname,"docTtl":poi3dStorageDocument.getTitle(),"docAttributes":JSON.stringify(attributes),"docData":docData};
          try
          {
            documentStore.put(documentToSave);
          }
          catch
          {
            resolve(-1);
          }

          resolve(0);

        }.bind(this);
      }.bind(this);//docRequest.onsuccess

      docRequest.onupgradeneeded = function(event)
      {
        let browserStorage = event.target.result;
        var modelObjectStore = browserStorage.createObjectStore("Documents", { keyPath: "docId" });
      };//docRequest.onupgradeneeded

    });//dbPromise = new Promise

    return await dbPromise;
  };//Poi3dStorageConnector.saveDocumentToBrowserStorageDb

  this.readDocumentFromBrowserDb = async function(docId,skipDbSearch)
  {
    if(skipDbSearch == true)
      return null;

    let dbPromise = new Promise(function(resolve)
    {
      window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
      window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
      window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;

      var docRequest = window.indexedDB.open("Poi3dBrowserStorageDb");

      docRequest.onerror = function(event)
      {
        resolve(null);
      };//docRequest.onerror

      docRequest.onsuccess = function(event)
      {
        let browserStorage = docRequest.result;

        let documentStore = browserStorage.transaction("Documents", "readwrite").objectStore("Documents");

        documentStore.openCursor().onsuccess = function(event)
        {
          var cursor = event.target.result;
          var storedModel = null;

          if (cursor)
          {
            if(cursor.key == docId)
              resolve(cursor.value);
            else
              cursor.continue();
          }
          else
            resolve(null);

        }.bind(this);//modelStore.openCursor().onsuccess
      }.bind(this);//docRequest.onsuccess

      docRequest.onupgradeneeded = function(event)
      {
        let browserStorage = event.target.result;
        var modelObjectStore = browserStorage.createObjectStore("Documents", { keyPath: "docId" });
      };//docRequest.onupgradeneeded
    });//dbPromise = new Promise

    return await dbPromise;
  };//Poi3dStorageConnector.readDocumentFromBrowserStorageDb

  this.updateStateTexts = function (message, style)
  {
    if(this.updateStateCb != null) this.updateStateCb(message,style);
  }
};//Poi3dStorageConnector
