// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+

#pragma once

#include <wx/arrstr.h>

#include <vector>
#include <set>
#include <memory>

#include "DemodulatorInstance.h"


class DataNode;

class BookmarkEntry {
public:
 
    std::string type;
	//maps on the Demod user label.
    std::wstring label; 
    
    long long frequency;
    int bandwidth;
    
    DataNode *node;
    
    virtual ~BookmarkEntry();
};


class BookmarkRangeEntry {
public:
    BookmarkRangeEntry() : label(L""), freq(0), startFreq(0), endFreq(0) {
        
    }
    BookmarkRangeEntry(std::wstring label, long long freq, long long startFreq, long long endFreq) : label(label), freq(freq), startFreq(startFreq), endFreq(endFreq) {
    }
     
    std::wstring label;
    
    long long freq;
    long long startFreq;
    long long endFreq;
};

typedef std::shared_ptr<BookmarkEntry> BookmarkEntryPtr;
typedef std::shared_ptr<BookmarkRangeEntry> BookmarkRangeEntryPtr;

struct BookmarkEntryCompare : public std::binary_function<BookmarkEntryPtr,BookmarkEntryPtr,bool>
{
    bool operator()(const BookmarkEntryPtr a, BookmarkEntryPtr b) const
    {
        return a->frequency < b->frequency;
    }
};


struct BookmarkRangeEntryCompare : public std::binary_function<BookmarkRangeEntryPtr ,BookmarkRangeEntryPtr ,bool>
{
    bool operator()(const BookmarkRangeEntryPtr a, BookmarkRangeEntryPtr b) const
    {
        return a->freq < b->freq;
    }
};

typedef std::vector<BookmarkEntryPtr> BookmarkList;
typedef std::vector<BookmarkRangeEntryPtr> BookmarkRangeList;
typedef std::map<std::string, BookmarkList > BookmarkMap;
typedef std::map<std::string, bool > BookmarkMapSorted;
typedef std::vector<std::string> BookmarkNames;
typedef std::map<std::string, bool> BookmarkExpandState;

class BookmarkMgr {
public:
    BookmarkMgr();
    //if useFullpath = false, use the application config dir.
	//else assume bookmarkFn is a full path and use it for location.
    void saveToFile(std::string bookmarkFn, bool backup = true, bool useFullpath = false);
    bool loadFromFile(std::string bookmarkFn, bool backup = true, bool useFullpath = false);

	void resetBookmarks();

    bool hasLastLoad(std::string bookmarkFn);
    bool hasBackup(std::string bookmarkFn);

    void addBookmark(std::string group, DemodulatorInstancePtr demod);
    void addBookmark(std::string group, BookmarkEntryPtr be);
    void removeBookmark(std::string group, BookmarkEntryPtr be);
    void removeBookmark(BookmarkEntryPtr be);
    void moveBookmark(BookmarkEntryPtr be, std::string group);
    
    void addGroup(std::string group);
    void removeGroup(std::string group);
    void renameGroup(std::string group, std::string ngroup);
	//return an independent copy on purpose 
    BookmarkList getBookmarks(std::string group);

    void getGroups(BookmarkNames &arr);
    void getGroups(wxArrayString &arr);

    void setExpandState(std::string groupName, bool state);
    bool getExpandState(std::string groupName);

    void updateActiveList();
    void updateBookmarks();
    void updateBookmarks(std::string group);

    void addRecent(DemodulatorInstancePtr demod);
    void addRecent(BookmarkEntryPtr be);
    void removeRecent(BookmarkEntryPtr be);
    
	//return an independent copy on purpose 
	BookmarkList getRecents();

    void clearRecents();

	void removeActive(DemodulatorInstancePtr demod);

    void addRange(BookmarkRangeEntryPtr re);
    void removeRange(BookmarkRangeEntryPtr re);

	//return an independent copy on purpose 
	BookmarkRangeList getRanges();
    
	void clearRanges();

    static std::wstring getBookmarkEntryDisplayName(BookmarkEntryPtr bmEnt);
    static std::wstring getActiveDisplayName(DemodulatorInstancePtr demod);

    
protected:

    void trimRecents();
	void loadDefaultRanges();

    //utility method that attemts to decode the childNodeName as std::wstring, else as std::string, else 
    //return an empty string.
    static std::wstring getSafeWstringValue(DataNode* node, const std::string& childNodeName);
    
    BookmarkEntryPtr demodToBookmarkEntry(DemodulatorInstancePtr demod);
    BookmarkEntryPtr nodeToBookmark(DataNode *node);
    
    BookmarkMap bmData;
    BookmarkMapSorted bmDataSorted;
    BookmarkList recents;
    BookmarkRangeList ranges;
    bool rangesSorted;

    std::recursive_mutex busy_lock;
    
    BookmarkExpandState expandState;
};
