// This file describes a model of the contents of the Challenge CSV.  
// It has been written and structured to cover the full set of columns, as well
// as to illustrate different features and potential usage patterns.
// 
// This is a standard SysML v2 file that simply uses certain (library-defined)
// definitions, which are then interpreted by our data processing software. As
// such, any (textual) SysML v2 editor (such as our own open-source SysIDE Editor)
// can be used to author this file, with functionality such as auto-completion,
// validation, and syntax highlighting.
// 
// Lines starting with // or text between /* ... */ are comments.
//
// While it is intended to be maintained by whoever is describing the dataset,
// it is not primarily intended to be the entry point for a user, who is generally
// better off reading some derived artifact.
package SemanticChallange {
    private import ScalarValues::String;

    // The Tabular library defines a single sort of metadata (tabular) that is used to indicate
    // that *instances* of a general SysML thing appear in a (specific) CSV file.
    private import Tabular::tabular;

    // The Ontological library defines three sorts of metdata:
    // - ontoclass: Indicating that instances of a general SysML thing are to be interpreted
    //   as also being instances of another resource, identified by a URI. Typically
    //   this would be an RDF/OWL class.
    //   E.g.: item def SomeSortOfPerson { metadata ontoclass { uri = "https://schema.org/Person" } }
    //   would indicate that anything identified as SomeSortOfPerson should also be interpreted as
    //   being a schema:Person.
    // - ontorel: Indicating that the source and target of a feature of some general SysML thing are to be
    //   interpreted as being related by some other resource, identified by a URI. Typically this
    //   would be some RDF/OWL predicate.
    //   E.g. item def SomeSortOfPerson { attribute name : String { metadata ontorel { uri = "https://schema.org/Person/name"; } } }
    // - atomic: Indicating that instances of a general SysML thing can also be identified by some
    //   IRI that can be derived from values of the instance's features.
    //   E.g. item def Film { /* .. */  metadata atomic { uri_pattern = "https://example.com/{year}/{title}"; } }
    //   Would indicate that a Film with features title "C'era una volta il West" and year "1968" would
    //   be interpreted as being identified by the uri https://example.com/1968/C%27era%20una%20volta%20il%20West
    private import Ontological::ontoclass;
    private import Ontological::ontorel;
    private import Ontological::atomic;

    // To begin with, we define some (SysML v2) definitions that we will
    // refer to later.
    //
    // Note that many of them are annotated with some combination of:
    // - metadata ontoclass {
    //       uri = "...";
    //   }
    // - metadata ontorel {
    //       uri = "...";
    //   }
    // - metadata ontoatomic {
    //       uri_pattern = "...";
    //   }
    //
    // See above for descriptions of how to interpret them.
    //
    // The main part of the description begins with the line
    // `item def ChallangeFDICInsuredBank`
    item def ChallangeAddress {
        doc
        /* A registered postal address appearing in the dataset */

        metadata ontoclass {
            uri =
                "https://spec.edmcouncil.org/fibo/ontology/FND/Places/Addresses/ConventionalStreetAddress";
        }
    }

    item def ChallangeOffice {
        doc
        /* A branch/office of a bank in the dataset */

        metadata ontoclass {
            uri =
                "https://spec.edmcouncil.org/fibo/ontology/FND/Places/Addresses/Office";
        }
    }

    item def ChallangeState {
        doc
        /* A US state appearing in the dataset */

        metadata ontoclass {
            uri = "https://www.omg.org/spec/Commons/Locations/State";
        }

        attribute name : String {
            metadata ontorel {
                uri =
                    "https://www.omg.org/spec/Commons/Designators/hasTextualName";
            }
        }

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/us_state/{name}";
        }
    }

    item def ChallangeCounty {
        doc
        /* A US county appearing in the dataset */

        metadata ontoclass {
            uri = "https://www.omg.org/spec/Commons/Locations/County";
        }

        // NOTE: single quotes (') because state is a SysML keyword.
        ref 'state' : ChallangeState {
            doc
            /* The state in which the county is located */

            metadata ontorel {
                uri = "https://www.omg.org/spec/Commons/Collections/hasPart";
            }
        }

        attribute name : String {
            doc
            /* The textual name of the county */

            metadata ontorel {
                uri =
                    "https://www.omg.org/spec/Commons/Designators/hasTextualName";
            }
        }

        // NOTE: the use of SysML feature chains ('state'.name) to refer to a feature
        // (name) of a feature (state). See below.
        state_name : String = 'state'.name;

        metadata atomic {
            // NOTE: We use the indirect stat_name = 'state'.name feature to distinguish counties
            // that share a name with a county in another state.
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/us_county/{state_name}/{name}";
        }
    }

    // NOTE: This datatype represents single (spatial) points *in the dataset*,
    // thus the coordinate frame does not need to be stored as an attribute.
    attribute def ChallangeLocation {
        doc
        /* A location (in the US) appearing in the dataset, primarily defined by being part of
         * one or more statistical areas
         */

        metadata ontoclass {
            uri =
                "http://www.opengis.net/ont/geosparql#SpatialObject";
        }

        statistical_area : ChallangeStatisticalArea {
            doc
            /* US statistical regions that the location is in */

            metadata ontorel {
                uri =
                    "http://www.opengis.net/ont/geosparql#ehInside";
            }
        }
    }

    attribute def ChallangePoint {
        doc
        /* A geographic point appearin in the dataset */

        metadata ontoclass {
            uri = "http://www.opengis.net/ont/sf#Point";
        }

        attribute latitude : String {
            metadata ontorel {
                uri = "http://www.w3.org/2003/01/geo/wgs84_pos#lat";
            }
        }
        attribute longitude : String {
            metadata ontorel {
                uri = "http://www.w3.org/2003/01/geo/wgs84_pos#long";
            }
        }
    }

    item def ChallangeServiceType {
        doc
        /* A service-type classification appearing in the dataset */

        metadata ontoclass {
            uri = "https://www.omg.org/spec/Commons/Organizations/Service";
        }

        attribute service_type_id : String;
        attribute service_type_description : String {
            doc
            /* Textual description of the service type */

            metadata ontorel {
                uri = "http://www.w3.org/2000/01/rdf-schema#comment";
            }
        }

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/service_type/{service_type_id}";
        }
    }

    item def ChallangeMinorityStatus {
        doc
        /* A minority status indicator appearing in the dataset */

        metadata ontoclass {
            uri =
                "https://www.sensmetry.com/omg_semantic_challange_2025/minority_status";
        }

        attribute code : String;

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/service_type/{code}";
        }
    }

    item def ChallangeStatisticalArea {
        doc
        /* A US geographic area division for statistical purposes */
        metadata ontoclass {
            uri =
                "http://www.opengis.net/ont/geosparql#SpatialObject";
        }

        attribute name : String {
            metadata ontorel {
                uri =
                    "https://www.omg.org/spec/Commons/Designators/hasTextualName";
            }
        }

        attribute code : String {
            metadata ontorel {
                uri =
                    "https://www.omg.org/spec/Commons/Identifiers/isIdentifiedBy";
            }
        }
    }

    item def ChallangeCombinedStatisticalArea :> ChallangeStatisticalArea {
        doc
        /* https://en.wikipedia.org/wiki/Combined_statistical_area */

        metadata ontoclass {
            uri =
                "https://spec.edmcouncil.org/fibo/ontology/IND/EconomicIndicators/EconomicIndicators/CombinedStatisticalArea";
        }

        :>> code;

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/csa/{code}";
        }
    }

    item def ChallangeCoreBasedStatisticalArea :> ChallangeStatisticalArea {
        doc
        /* https://en.wikipedia.org/wiki/List_of_core-based_statistical_areas */
    }

    item def ChallangeMetropolitanStatisticalArea
        :> ChallangeCoreBasedStatisticalArea {
        doc
        /* https://en.wikipedia.org/wiki/Metropolitan_statistical_area */

        metadata ontoclass {
            uri =
                "https://spec.edmcouncil.org/fibo/ontology/IND/EconomicIndicators/EconomicIndicators/MetropolitanStatisticalArea";
        }

        :>> code;

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/cbsa_metro/{code}";
        }
    }

    item def ChallangeMetropolitanDivisionStatisticalArea
        :> ChallangeCoreBasedStatisticalArea {
        metadata ontoclass {
            uri =
                "https://www.sensmetry.com/omg_semantic_challange_2025/cbsa_div";
        }

        :>> code;

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/cbsa_metro_div/{code}";
        }
    }

    item def ChallangeMicropolitanStatisticalArea
        :> ChallangeCoreBasedStatisticalArea {
        doc
        /* https://en.wikipedia.org/wiki/Micropolitan_statistical_area */

        metadata ontoclass {
            uri =
                "https://spec.edmcouncil.org/fibo/ontology/IND/EconomicIndicators/EconomicIndicators/MicropolitanStatisticalArea";
        }

        :>> code;

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/cbsa_micro/{code}";
        }
    }

    item def ChallangeInstitutionClass {
        metadata ontoclass {
            uri =
                "https://www.sensmetry.com/omg_semantic_challange_2025/institution_class";
        }

        attribute abbreviation : String;

        metadata atomic {
            uri_pattern =
                "https://www.sensmetry.com/omg_semantic_challange_2025/institution_class/{abbreviation}";
        }
    }



    // We describe the dataset in a nested fashion, with banks having offices as parts, ...
    // This has little or no effect on the final RDF/TTL representation but helps structure
    // this document itself and makes it easier to read.
    item def ChallangeFDICInsuredBank {
        doc
        /* These are the banks appearing in the dataset */

        metadata tabular {
            // We specify a URI identifying the file, all that `tabular`s below
            // inherit it, so that we need not repeat it.
            //
            // Currently the prototype tooling only supports local `file` URLs. 
            uri = "file:./FDIC_Insured_Banks.csv";
            // `key` indicates a set of columns that uniquely identify each instance
            // of (in this case) a Bank in the dataset.
            // In this example, there are redundant columns (FI_UNINUM and CERT). This is
            // intentional, as it improves the generated documentation.
            key = ("NAME", "FI_UNINUM", "CERT");
            // `name_hint` just gives a general hint for how to label instances (of banks).
            // you need not ensure it unique (there are distinct banks that share name).
            // It is the responsibility of the implementation to add/derive unique names for
            // distinct instances. This is simply a hint to the implementation for how to
            // get something that is easier for humans to interpret.
            name_hint = "{NAME}";

            // Just two examples of additional metadata
            provider = "Federal Deposit Insurance Corporation, Division of Insurance and Research";
            fetched_from = "https://hub.arcgis.com/datasets/geoplatform::fdic-insured-banks";
        }

        metadata ontoclass {
            // This indicates that any instance (bank) should be taken as being an instance of
            // the (FIBO ontology) class Bank.
            uri =
                "https://spec.edmcouncil.org/fibo/ontology/FBC/FunctionalEntities/FinancialServicesEntities/Bank";
        }

        metadata atomic {
            // This indicates that each intance (bank) can be uniquely identified by, here, a link
            // to the FDIC certification page.
            uri_pattern =
                "https://banks.data.fdic.gov/bankfind-suite/bankfind/details/{fdic_cert_number}";
        }

        institution_class : ChallangeInstitutionClass {
            // This is a (reference) feature called `institution_class`, associating ChallangeInstitutionClass(s)
            // to each ChallangeFDICInsuredBank.
            // Instances are identified by unique values of the BKCLASS column, meaning there will be
            // exactly one instance for each value.
            //
            // When two distinct banks appear with the same BKCLASS column value, this will be interpreted
            // as both referencing *the same* ChallangeInstitutionClass instance.
            metadata tabular {
                key = "BKCLASS";
            }

            // This indicates that the fact that a ChallangeFDICInsuredBank being related to a ChallangeInstitutionClass
            // implies that they are related by https://www.sensmetry.com/omg_semantic_challange_2025/has_institution_class.
            // Practically, this means that whenever the Bank and the Institution class themselves are RDF resources (identified
            // by uri_Bank and uri_institution_class), then the software will assert the tripple
            //   (uri_bank, https://www.sensmetry.com/omg_semantic_challange_2025/has_institution_class, uri_institution_class)  
            metadata ontorel {
                uri =
                    "https://www.sensmetry.com/omg_semantic_challange_2025/has_institution_class";
            }

            // This "stores" the BKCLASS column value as the `abbreviation` feature from ChallangeInstitutionClass/
            // `:>> abbreviation` is a SysML v2 notation to say that we are defining a feature that redefines
            // the feature `abbreviation` (here inherited from ChallangeInstitutionClass).
            //
            // Since ChallangeInstitutionClass is marked as atomic, with
            // uri_pattern = "https://www.sensmetry.com/omg_semantic_challange_2025/institution_class/{abbreviation}"
            // we will get instances identified by IRIs:
            // https://www.sensmetry.com/omg_semantic_challange_2025/institution_class/UNIQUE_BKCLASS_COLUMN_VALUE_1
            // https://www.sensmetry.com/omg_semantic_challange_2025/institution_class/UNIQUE_BKCLASS_COLUMN_VALUE_2
            // ...
            :>> abbreviation {
                metadata tabular {
                    key = "BKCLASS";
                }
            }
        }

        attribute fdic_cert_number : String {
            // This is an String attribute feature, similar to the institution_class example above,
            // except that its range is a DataType (so we need not worry about distinctness as the string
            // "12345" is equal to any other string "12345").
            metadata tabular {
                key = "CERT";
            }
        }

        attribute name : String {
            metadata tabular {
                key = "NAME";
            }

            metadata ontorel {
                uri = "https://schema.org/name";
            }
        }

        // main_office becomes a (nominally) separate model element but gets
        // unified at the RDF-level as it gets the same IRI.
        part main_office :> office {
            metadata tabular {
                key = ("MAINOFF", "OFFNUM", "UNINUM");
                name_hint = "Main office";
                // This indicates to only consider combinations of
                // MAINOFF, OFFNUM, UNINUM
                // where
                // MAINOFF is not "0"
                unless = "0";
            }

            :>> uninum : String {
                metadata tabular {
                    key = "UNINUM";
                }
            }

            metadata ontorel {
                uri =
                    "https://www.sensmetry.com/omg_semantic_challange_2025/has_main_office";
            }
        }

        part office : ChallangeOffice {
            // Office is a (composite) part feature of ChallangeFDICInsuredBank. Conceptually we think of
            // a bank as being consistuted by (among other things) a number of `ChallangeOffice`s, with the office
            // feature "enumerating" those offices.

            doc /* A branch office of the bank */

            // Each office is identified by a number of different identifiers. Either one of OBJECTID,
            // OFFNUM, UNINUM, and ID would have sufficed. Mentioning all of them (as well as OFFNAME)
            // helps document the redundant columns.
            metadata tabular {
                key = ("OBJECTID", "OFFNUM", "UNINUM", "OFFNAME", "ID");
                name_hint = "{OFFNAME}";
            }

            attribute uninum : String {
                metadata tabular {
                    key = "UNINUM";
                }
            }

            metadata atomic {
                uri_pattern =
                    "https://www.sensmetry.com/omg_semantic_challange_2025/office/{uninum}";
            }

            metadata ontoclass {
                uri =
                    "https://spec.edmcouncil.org/fibo/ontology/BE/LegalEntities/FormalBusinessOrganizations/Branch";
            }

            metadata ontorel {
                uri = "https://www.omg.org/spec/Commons/Collections/hasPart";
            }

            // `name` (as well as `uninum` above) are examples of features 
            // that are declared part of each `office`, without being features of
            // the range type (ChallangeOffice).
            // `name` still get picked up in the final RDF document since it is
            // annotated with an `ontorel` metadata. 
            attribute name : String {
                metadata tabular {
                    key = "OFFNAME";
                    unless = "None Given";
                }

                metadata ontorel {
                    uri = "https://schema.org/name";
                }
            }

            // NOTE: The original CSV contains coding errors here. These
            // are dealt with separately, as there are better, well established
            // tools for data cleaning.
            attribute established : String {
                doc /* Date at which the office was established. */
                metadata tabular {
                    key = "ESTYMD";
                }
            }

            attribute acquired : String {
                doc /* Date at which the office was most recently acquired. */
                metadata tabular {
                    key = "ACQDATE";
                    unless = "";
                }
            }

            attribute location : ChallangeLocation {
                doc /* The location of the office */
                metadata tabular {
                    key = "UNINUM";
                }

                metadata ontorel {
                    uri = "http://purl.org/dc/terms/location";
                }

                // All three of
                // - combined_statistical_area
                // - micropolitan_core_based_statistical_area
                // - metropolitan_core_based_statistical_area
                // - metropolitan_division_core_based_statistical_area
                // *subset* statistical_area (as indicated by :>)
                // As such, all CSAs, Micropolitcan CBSAs, etc will be
                // picked up as areas that the location is partOf.
                combined_statistical_area
                    :> statistical_area : ChallangeCombinedStatisticalArea {
                    doc /* The https://en.wikipedia.org/wiki/Combined_statistical_area in which the
                         * office location is located (if any). */
                    metadata tabular {
                        key = ("CSA_FLG", "CSA_NO", "CSA");
                        name_hint = "{CSA} ({CSA_NO})";
                        unless = "0";
                    }

                    :>> code {
                        metadata tabular {
                            key = "CSA_NO";
                        }
                    }
                }

                micropolitan_core_based_statistical_area
                    :> statistical_area : ChallangeMicropolitanStatisticalArea {
                    metadata tabular {
                        key = ("CBSA_MICRO_FLG", "CBSA_NO", "CBSA");
                        name_hint = "{CBSA} ({CBSA_NO})";
                        unless = "0";
                    }

                    :>> code {
                        metadata tabular {
                            key = "CBSA_NO";
                        }
                    }
                }

                metropolitan_core_based_statistical_area
                    :> statistical_area : ChallangeMetropolitanStatisticalArea {
                    metadata tabular {
                        key = (
                            "CBSA_METRO_FLG", "CBSA_METRO", "CBSA_METRO_NAME",
                            "CBSA_NO", "CBSA"
                        );
                        name_hint = "{CBSA_METRO_NAME} ({CBSA_METRO})";
                        unless = "0";
                    }

                    :>> code {
                        metadata tabular {
                            key = "CBSA_METRO";
                        }
                    }
                }

                metropolitan_division_core_based_statistical_area
                    :> statistical_area
                    : ChallangeMetropolitanDivisionStatisticalArea {
                    metadata tabular {
                        key = ("CBSA_DIV_FLG", "CBSA_DIV_NO", "CBSA_DIV");
                        name_hint = "{CBSA_DIV} ({CBSA_DIV_NO})";
                        unless = "0";
                    }

                    :>> code {
                        metadata tabular {
                            key = "CBSA_DIV_NO";
                        }
                    }
                }

                attribute point : ChallangePoint {
                    doc /* The geographic location approximated by one point */

                    metadata tabular {
                        key = ("LATITUDE", "LONGITUDE", "X", "Y");
                    }

                    metadata ontorel {
                        uri = "http://w3.org/ns/locn#geometry";
                    }

                    :>> latitude {
                        // TODO: Figure out how to have X and Y here too
                        metadata tabular {
                            key = "LATITUDE";
                        }
                    }

                    :>> longitude {
                        metadata tabular {
                            key = "LONGITUDE";
                        }
                    }
                }
            }

            item address : ChallangeAddress {
                doc /* The office's registered address */
                metadata tabular {
                    key = (
                        "ADDRESS", "ADDRESS2", "CITY", "COUNTY", "STNAME", "ZIP"
                    );
                }

                metadata ontorel {
                    uri =
                        "https://spec.edmcouncil.org/fibo/ontology/BE/LegalEntities/FormalBusinessOrganizations/hasRegisteredAddress";
                }

                attribute address_line_1 : String {
                    metadata tabular {
                        key = "ADDRESS";
                    }

                    metadata ontorel {
                        uri =
                            "https://spec.edmcouncil.org/fibo/ontology/FND/Places/Addresses/hasAddressLine1";
                    }
                }

                attribute address_line_2 : String {
                    metadata tabular {
                        key = "ADDRESS2";
                        unless = "";
                    }

                    metadata ontorel {
                        uri =
                            "https://spec.edmcouncil.org/fibo/ontology/FND/Places/Addresses/hasAddressLine2";
                    }
                }

                attribute city_name : String {
                    metadata tabular {
                        key = "CITY";
                        name_hint = "{CITY}";
                    }

                    metadata ontorel {
                        uri =
                            "https://www.omg.org/spec/Commons/Locations/hasCityName";
                    }
                }

                county : ChallangeCounty {
                    metadata tabular {
                        key = ("COUNTY", "STCNTY");
                        name_hint = "{COUNTY}";
                        unless = "Not Supplied";
                    }

                    metadata ontorel {
                        uri =
                            "https://www.omg.org/spec/Commons/Locations/hasCounty";
                    }

                    :>> name {
                        metadata tabular {
                            key = "COUNTY";
                        }
                    }

                    :>> 'state' {
                        metadata tabular {
                            key = ("STNAME", "STALP");
                            name_hint = "{STNAME}";
                            unless = ("", "");
                        }

                        :>> name {
                            metadata tabular {
                                key = "STNAME";
                            }
                        }
                    }
                }

                // Note that the original CSV contains coding errors here (codes are sometimes
                // padded and sometimes not). They are treated separately, as there are more
                // appropriate tools for data cleaning.
                minority_status : ChallangeMinorityStatus {
                    metadata tabular {
                        key = ("MDI_STATUS_CODE", "MDI_STATUS_DESC");
                        name_hint = "{MDI_STATUS_CODE}: {MDI_STATUS_DESC}";
                        unless = ("", "NULL");
                    }

                    :>> code {
                        metadata tabular {
                            key = "MDI_STATUS_CODE";
                        }
                    }

                    attribute description : String {
                        metadata tabular {
                            key = "MDI_STATUS_DESC";
                        }

                        metadata ontorel {
                            uri =
                                "http://www.w3.org/2000/01/rdf-schema#comment";
                        }
                    }
                }

                attribute zip : String {
                    metadata tabular {
                        key = "ZIP";
                        unless = "0";
                    }

                    metadata ontorel {
                        uri =
                            "https://spec.edmcouncil.org/fibo/ontology/FND/Places/Addresses/hasPostalCode";
                    }
                }
            }

            service_type : ChallangeServiceType {
                metadata tabular {
                    key = ("SERVTYPE", "SERVTYPE_DESC");
                    name_hint = "{SERVTYPE}: {SERVTYPE_DESC}";
                }

                :>> service_type_id : String {
                    metadata tabular {
                        key = "SERVTYPE";
                    }
                }

                :>> service_type_description : String {
                    metadata tabular {
                        key = "SERVTYPE_DESC";
                    }
                }

                metadata ontorel {
                    uri =
                        "https://www.omg.org/spec/Commons/Organizations/provides";
                }
            }
        }
    }

    item def ChallangeRunDate {
        doc
        /* Appears to be an unused artifact of how the file was produced. */
        metadata tabular {
            uri = "file:./FDIC_Insured_Banks.csv";
            key = "RUNDATE";
            unless = "45401";
        }
    }
}
