// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved. // Use of this source code is governed by a MIT-style license that can // be found in the LICENSE file. package mop import ( `encoding/json` `io/ioutil` `os/user` `sort` ) // File name in user's home directory where we store the settings. const moprc = `/.moprc` // Profile manages Mop program settings as defined by user (ex. list of // stock tickers). The settings are serialized using JSON and saved in // the ~/.moprc file. type Profile struct { Tickers []string // List of stock tickers to display. MarketRefresh int // Time interval to refresh market data. QuotesRefresh int // Time interval to refresh stock quotes. SortColumn int // Column number by which we sort stock quotes. Ascending bool // True when sort order is ascending. Grouped bool // True when stocks are grouped by advancing/declining. selectedColumn int // Stores selected column number when the column editor is active. } // Initialize attempts to load the settings from ~/.moprc file. If the // file is not there it gets created with the default values. func (profile *Profile) Initialize() *Profile { data, err := ioutil.ReadFile(profile.defaultFileName()) if err != nil { // Set default values: profile.MarketRefresh = 12 // Market data gets fetched every 12s (5 times per minute). profile.QuotesRefresh = 5 // Stock quotes get updated every 5s (12 times per minute). profile.Grouped = false // Stock quotes are *not* grouped by advancing/declining. profile.Tickers = []string{ `AAPL`, `C`, `GOOG`, `IBM`, `KO`, `ORCL`, `V` } profile.SortColumn = 0 // Stock quotes are sorted by ticker name. profile.Ascending = true // A to Z. profile.Save() } else { json.Unmarshal(data, profile) } profile.selectedColumn = -1 return profile } // Save serializes settings using JSON and saves them in ~/.moprc file. func (profile *Profile) Save() error { data, err := json.Marshal(profile) if err != nil { return err } return ioutil.WriteFile(profile.defaultFileName(), data, 0644) } // AddTickers updates the list of existing tikers to add the new ones making // sure there are no duplicates. func (profile *Profile) AddTickers(tickers []string) (added int, err error) { added, err = 0, nil existing := make(map[string]bool) // Build a hash of existing tickers so we could look it up quickly. for _, ticker := range profile.Tickers { existing[ticker] = true } // Iterate over the list of new tickers excluding the ones that // already exist. for _, ticker := range tickers { if _, found := existing[ticker]; !found { profile.Tickers = append(profile.Tickers, ticker) added++ } } if added > 0 { sort.Strings(profile.Tickers) err = profile.Save() } return } // RemoveTickers removes requested stock tickers from the list we track. func (profile *Profile) RemoveTickers(tickers []string) (removed int, err error) { removed, err = 0, nil for _, ticker := range tickers { for i, existing := range profile.Tickers { if ticker == existing { // Requested ticker is there: remove i-th slice item. profile.Tickers = append(profile.Tickers[:i], profile.Tickers[i+1:]...) removed++ } } } if removed > 0 { err = profile.Save() } return } // Reorder gets called by the column editor to either reverse sorting order // for the current column, or to pick another sort column. func (profile *Profile) Reorder() error { if profile.selectedColumn == profile.SortColumn { profile.Ascending = !profile.Ascending // Reverse sort order. } else { profile.SortColumn = profile.selectedColumn // Pick new sort column. } return profile.Save() } // Regroup flips the flag that controls whether the stock quotes are grouped // by advancing/declining issues. func (profile *Profile) Regroup() error { profile.Grouped = !profile.Grouped return profile.Save() } //----------------------------------------------------------------------------- func (profile *Profile) defaultFileName() string { usr, err := user.Current() if err != nil { panic(err) } return usr.HomeDir + moprc }