text: import {
      reactive,
      computed,
      watch
  } from 'vue'
  
  class ThemeManager {
      constructor(options) {
          this.onThemeChangedListener = null;
          this.ThemeChangerWatcher = null;
          this.onReadyListener = null;
          this.theme = reactive({
              name: 'default',
              names: computed(() => {
                  return this.getnames()
              }),
              default: {},
              currentTheme: computed(() => {
                  return this.theme[this.theme.name]
              }),
          })
  
          //update current theme keys
          watch(() => this.theme.currentTheme, (newval, oldval) => {
              this.updateThemeTree(newval, oldval);
  
          });
          this.init(options);
          this.updateThemeTree(this.theme.currentTheme);
      }
  
      init(options) {
  
          try {
              JSON.parse(options)
          } catch (err) {}
  
          if (options !== undefined && typeof options === 'object') {
              this.theme.name = options.activate == undefined ? this.theme.name : options.activate
              let keys = Object.keys(options.styles);
              for (let c = 0; c < keys.length; c++) {
                  Object.defineProperty(this.theme, keys[c], {
                      value: options.styles[keys[c]],
                      writable: true,
                      enumerable: true
                  });
              }
              let currtheme = this.theme.name;
              this.theme.name = '' // to make
              this.theme.name = currtheme; // the changed reactibe
  
          }
  
      }
      setReadyListener() {
          try {
              this.onReadyListener(this.hasThemeInDB());
          } catch (err) {}
      }
  
      setThemeChangeListener(callback) {
          this.ThemeChangerWatcher = callback || function () {}
      }
  
      onReady(callback) {
          this.onReadyListener = callback || function () {}
      }
      onThemeChanged(callback) {
          this.onThemeChangedListener = callback || function () {}
      }
  
      updateThemeTree(newval = [], oldval = []) {
          //deleting old keys
          let currentKeys = Object.keys(oldval);
          for (var x = 0; x < currentKeys.length; x++) {
              let key = currentKeys[x];
              this.theme[key] = undefined
          }
  
  
          //adding new keys
          let newkeys = Object.keys(newval);
          for (var x = 0; x < newkeys.length; x++) {
              let key = newkeys[x];
              //console.log(key)
              Object.defineProperty(this.theme, key, {
                  value: this.theme.currentTheme[key],
                  enumerable: true,
                  writable: true
              });
          }
          //delete old values
          //add new values
      }
  
      getnames() {
          var result = [];
          let keys = Object.keys(this.theme);
          for (var x = 0; x < keys.length; x++) {
              let key = keys[x]
              if (typeof this.theme[key] === 'object' && key != 'currentTheme' && !Array.isArray(this.theme[key])) {
                  result.push(key)
              }
          }
          return result //get names 
      }
  
      addTheme(style, themeName = 'default', activate = false) {
          if (activate) {
              this.theme.name = themeName
              try {
                  this.onThemeChangedListener(this.theme.name, this.theme.currentTheme);
              } catch (err) {};
          }
  
          if (typeof style !== 'object' && style !== null) {
              style = JSON.parse(style)
          } //convert to object if it is json string
  
          if (!this.theme.hasOwnProperty(themeName)) { //theme doesn't exist yet so we create one
  
              Object.defineProperty(this.theme, themeName, {
                  value: style,
                  enumerable: true,
                  writable: true
              })
              let currtheme = this.theme.name;
              this.theme.name = '' // to make
              this.theme.name = currtheme; // the changed reactibe
          } else {
              this.theme[themeName] = Object.assign({}, this.theme[themeName], style);
          }
          return this
  
      }
  
      activateTheme(name) {
          if (name != '' || name != null) {
              if (this.theme[name] !== undefined) {
                  this.theme.name = name
                  this.saveTheme();
                  //try{this.onThemeChangedListener(name,this.theme.currentTheme);}catch(err){};
                  this.ThemeChangerWatcher(name, this.theme.currentTheme);
              } else {
                  console.log('theme doesnt exist')
              }
          }
  
          return this
      }
  
      getTheme(themeName = this.theme.name, which) {
          if (this.theme[themeName] == undefined) {
              return
          }
          if (which == undefined || !Array.isArray(which)) { //return's full theme options
              return this.theme[themeName]
          }
  
          var result = {};
          for (let i = 0; i < which.length; i++) {
              let c = which[i]
              // console.log(JSON.stringify(this.theme['default']));
              try {
                  Object.defineProperty(result, c, {
                      value: this.theme[themeName][c],
                      writable: true,
                      enumerable: true
                  })
              } catch (err) {
                  console.log(err)
              }
  
          }
          return result;
      }
  
      saveTheme() {
          let db_theme = {
              activate: this.theme.name,
              styles: {}
          }
          for (let u = 0; u < this.theme.names.length; u++) {
              let ct = this.theme.names[u];
              //  console.log(ct)
              let theme = this.theme[ct];
              if (theme !== undefined && typeof theme === 'object' && !Array.isArray(theme)) {
                  //   console.log(JSON.stringify(theme))
                  Object.defineProperty(db_theme.styles, ct, {
                      value: theme,
                      enumerable: true,
                      writable: true
                  })
              }
          }
          //now we save to localStorage
          localStorage.setItem('VUE_THEME_MANAGER', JSON.stringify(db_theme));
          return this
      }
  
      setThemeFromStorage() {
          let th = localStorage.getItem('VUE_THEME_MANAGER');
          if (th !== null) {
              this.init(JSON.parse(th));
          }
          //get from localStorge then initialize
          return this
      }
  
  
      hasThemeInDB() {
          let th = localStorage.getItem('VUE_THEME_MANAGER');
          if (th !== null) {
              return true
          }
          return false
      }
  
      activateThemechangeListenser(name, options) {
          this.onThemeChangedListener(name, options);
      }
  
  
  }
  
  
  
  
  
  
  
  
  const VueThemeManager = {
      install(Vue, options) {
          Vue.config.globalProperties.$AppTheme = new ThemeManager(options);
          Vue.mixin({
              mounted() {
                  this.$AppTheme.setReadyListener();
                  this.$AppTheme.setThemeChangeListener((res) => {
                      this.$AppTheme.activateThemechangeListenser(res);
                  });
              },
              computed: {
                  VueThemeManager() {
                      let currentTheme = {};
                      var theme = this.$AppTheme.theme.currentTheme;
                      let keys = Object.keys(theme);
  
                      for (var i = 0; i < keys.length; i++) {
                          let ck = keys[i];
                          let cp = theme[ck];
                          let tokebalcase = ck.replace(/\B(?:([A-Z])(?=[a-z]))|(?:(?<=[a-z0-9])([A-Z]))/g, '-$1$2').toLowerCase(); //convert to --xxx-xx for css variables
                          Object.defineProperty(currentTheme, '--' + tokebalcase, {
                              value: cp,
                              enumerable: true,
                              writable: true
                          });
                      }
                      return currentTheme
                  }
              }
          });
      }
  }
  
  export default VueThemeManager;