#include <iostream>
#include <list>
#include <algorithm>

struct Snode
{
    char data;
    int count;
};

class set
{
private:
    std::list<Snode> nodes;

    auto findValue(char value)
    {
        return std::find_if(nodes.begin(), nodes.end(),
            [=](const Snode &n){ return (n.data == value); }
        );
    }

public:
    bool isAvailable(char value)
    {
        return (find(value) != nullptr);
    }

    Snode* find(char value)
    {
        auto iter = findValue(value);
        if (iter != nodes.end())
            return &*iter;
        return nullptr;
    }

    bool isFirst(char value)
    {
        return ((!nodes.empty()) && (nodes.front().data == value));
    }

    bool isLast(char value)
    {
        return ((!nodes.empty()) && (nodes.back().data == value));
    }

    void display()
    {
        for (auto &n : nodes)
            std::cout << n.data << " " << n.count << std::endl;
    }

    void insert(char value)
    {
        Snode *temp = find(value);
        if (temp)
            temp->count += 1;
        else
            nodes.push_back(Snode{value, 1});
    }

    int count(char value)
    {
        Snode *temp = find(value);
        return (temp) ? temp->count : 0;
    }

    void deleteFirst()
    {
        if (!nodes.empty())
            nodes.pop_front();
    }

    void deleteLast()
    {
        if (!nodes.empty())
            nodes.pop_back();
    }

    void remove(char value)
    {
        auto iter = findValue(value);
        if (iter != nodes.end())
        {
            if (iter->count > 1)
                iter->count -= 1;
            else
                nodes.erase(iter);
        }
    }   
};

int main()
{
    //defining a mySet as a "set" type
    set mySet;

    //adding values to create nodes
    mySet.insert('c');
    mySet.insert('a');
    mySet.insert('a');
    mySet.insert('c');
    mySet.insert('c');

    set myCopiedSet = mySet; // make a copy of the list

    //adding more values to create nodes
    myCopiedSet.insert('a');
    myCopiedSet.insert('b');
    myCopiedSet.insert('b');
    myCopiedSet.insert('c');

    // another test
    set myTestSet;
    myTestSet.insert('c');
    myTestSet.insert('c');
    myTestSet.insert('j');
    myTestSet.insert('j');
    myTestSet.insert('j');
    myTestSet.insert('r');

    //displaying nodes through "value count" format
    std::cout << "original:" << std::endl;
    mySet.display();    
    std::cout << "copy:" << std::endl;
    myCopiedSet.display();
    std::cout << "test:" << std::endl;
    myTestSet.display();

    return 0;
}