--@ Version: 1.0.2

--@ Author Luke Wigley

--@ Description
-- This script allows several objects to read and write their prefs (property/value pairs) to a
-- single pref file. To save prefs, an object needs to call the SaveObjectPrefs method, specifying
-- an id and a property list of property/value pairs to save. For example, if you had a script called
-- 'FileBrowser' and you want to save the last Directory the user selected, you could do this:
--
--    Prefs = script("PrefUtility")
--    Prefs.SaveObjectPrefs("FileBrowser", [#LastPath: myLastPath])
--
-- To get prefs, an object calls the GetObjectPrefs() method, passing the id and a reference to itself.
-- The values are set directly into the object. For example, the 'FileBrowser' script could read (and
-- set) its prefs like this:
--
--    Prefs = script("PrefUtility")
--    Prefs.GetObjectPrefs("FileBrowser", me)
--
-- Note. You need to call the "WritePrefsFile" method to actually save the prefs to disk. For example:
--
--   on stopMovie
--     script("PrefUtility").WritePrefsFile()
--   end
--

--@ History
--
-- v.1.02
-- Added fix where saving a symbol would be restored as a string (by manually inserting the "#" character
-- before the symbol name.
--
--
-- v.1.01
-- Changed the way the script tests whether it can evaluate a string into a different type
-- It tests (1) whether the string starts with a quote (always treats this as a string; and
-- (2) whether the string version of an evaluation is the same as the original string.
--
-- v.1.00
-- First version.

-----------------------------------------



property myGlobalPrefList, myPrefFile


on GetObjectPrefs (me, id, obj)
  
-- Applies values extracted from the pref file to the specified object.
  --
  --* id is the id used to save the prefs {String}
  --* obj is the object to apply the values to {instance}
  --* return TRUE is some pref values were found {instance}

  if voidP(myPrefFile) then me.Init()
  pList = myGlobalPrefList.
getAProp(id)
  if voidP(pList) then
    put "Prefs not set for " & id
    return 0
  else
    repeat with
i = 1 to pList.count
      p = symbol(pList.getPropAt(i))
      v = pList[i]
      obj[p] = v
    end repeat
    return
1
  end if
end



on
SaveObjectPrefs (me, id, inList)
  
-- Stores the values in the specified list. The property names should
  -- match the property name in the object saving the prefs
  --
  --* id is the id used to save the prefs {String}
  --* inList is a property list {instance}


  if voidP(myPrefFile) then me.Init()
  pList = myGlobalPrefList.
getAProp(id)
  if voidP(pList) then
    pList = [:]
  end if
  repeat with
i = 1 to inList.count
    p = inList.getPropAt(i)
    v = inList[i]
    pList[p] = v
  end repeat
  myGlobalPrefList.setAProp(id, pList)
end


on
WritePrefsFile (me)
  
-- Call this method on stopMovie (etc) to actually write the
  -- the prefs to disk

  if voidP(myPrefFile) then me.Init()
  ps =
""
  repeat with i = 1 to myGlobalPrefList.count
    ps = ps & "$"&myGlobalPrefList.getPropAt(i) & return
    pList = myGlobalPrefList[i]
    repeat with j = 1 to pList.count
      p = pList.getPropAt(j)
      v = pList[j]
      if v.ilk = #Symbol then v = "#" & (v)
      ps = ps & p &
"=" & v & return
    end repeat
  end repeat
  -- put "Writing Prefs -->" & return & ps
  setPref (myPrefFile, ps)
end

-----------------------------------------


on new (me)
  
-- Note - this is a 'single instance' script (the script object
  -- is returned if you try to make a new instance)
  return me.script
end



on
PrefsExist (me, id)
  
-- A Method for checking whether of not some prefs exist for
  -- the specified ID.
  --* id which pref to check {String}
  --* return true if there is some data for specified id {instance}
  if voidP(myPrefFile) then me.Init()
  pList = myGlobalPrefList.
getAProp(id)
  return NOT(voidP(pList))
end









on
Init (me, PrefFile)
  
-- Manually load the prefs from disk and initialise the object.
  -- (If you do not do this, this script will automatically load the
  -- prefs from disk the first time you call any of its methods)
  --* PrefFile name of the prefile (otherwise, movie name is used) {string, optional}
  if voidP(PrefFile) then me._SetDefaultPrefFile()
  else myPrefFile = PrefFile
  myGlobalPrefList = [:]
  me._LoadPrefs()
end


-- PRIVATE



on _LoadPrefs(me)
  
-- Load the prefs from disk.

  if voidP(myPrefFile) then me.Init()
  ps =
getPref(myPrefFile)
  
-- put "Reading prefs ->" & return & ps
  if (ps.ilk = #String) then
    mx = ps.
line.count
    currentid = ""
    currentCollection = [:]
    repeat with i = 1 to mx
      thisline = ps.
line[i]
      if thisline starts "$" then -- new collection
        if currentid <> "" then -- save the old
          myGlobalPrefList.addProp(currentid, currentCollection)
        end if
        currentid = thisline.char[2..thisline.length]
        currentCollection = [:]
      else if currentid <> "" then
        slen =
length(thisline)
        p =
offset("=", thisline)
        if p > 1 AND p< slen then
          toSet =
symbol(thisline.char[1..p-1])
          theVal =
me._evalString(thisline.char[p+1..slen])
          currentCollection[toSet] = theVal
        end if
      end if
    end repeat
    if
currentid <> "" then
      myGlobalPrefList.
addProp(currentid, currentCollection)
    end if
  else
    myGlobalPrefList = [:]
  end if
end





on
_SetDefaultPrefFile (me)
  m =
the movieName
  the itemDelimiter = "."
  mx = m.item.count
  myPrefFile = (m.item[1..(mx-1)] & ".txt")
end

on
_evalString(me, aStr)
  if NOT(aStr starts QUOTE) then
    test1 =
value(aStr)
    if not voidP(test1) then
      if
symbolP(test1) then
        test2 =
"#"&test1
        if test2 = aStr then
          return test1
        end if
      else

        test2 =
string(test1)
        if test2 = test1 then
          return test1
        end if
      end if
    end if
  end if
  return
aStr
end