
enum ItemType {

    case general

    case post(Post)

    case feed

    case page(Page)

    case tagPage(Tag)

    case tagOverview
}

extension ItemType: Equatable {

}

extension ItemType: Hashable {

}

extension ItemType: Identifiable {

    var id: String {
        switch self {
        case .general:
            return "0-general"
        case .feed:
            return "1-feed"
        case .post(let post):
            return "2-post-\(post.id)"
        case .page(let page):
            return "3-page-\(page.id)"
        case .tagPage(let tag):
            return "5-tag-\(tag.id)"
        case .tagOverview:
            return "4-tag-overview"
        }
    }

    init?(rawValue: String, posts: [String : Post], pages: [String : Page], tags: [String : Tag]) {
        if rawValue == "0-general" {
            self = .general
        } else if rawValue == "1-feed" {
            self = .feed
        } else if rawValue == "4-tag-overview" {
            self = .tagOverview
        } else if let id = rawValue.removingPrefix("3-page-"), let page = pages[id] {
            self = .page(page)
        } else if let id = rawValue.removingPrefix("2-post-"), let post = posts[id] {
            self = .post(post)
        } else if let id = rawValue.removingPrefix("5-tag-"), let tag = tags[id] {
            self = .tagPage(tag)
        } else {
            return nil
        }
    }
}

extension ItemType: Comparable {

    static func < (lhs: ItemType, rhs: ItemType) -> Bool {
        lhs.id < rhs.id
    }
}

extension String {

    func removingPrefix(_ prefix: String) -> String? {
        guard self.hasPrefix(prefix) else { return nil }
        return String(self.dropFirst(prefix.count))
    }
}
