.InitExtensions <- function(where) {
    ## to be called from the initialization
    setClass("SClassExtension", representation(subClass = "character", superClass = "character", package = "character",
                                               coerce = "function", test = "function",
                                               replace = "function",
                                               simple = "logical", by = "character",
                                               dataPart = "logical"),
             where = where)
    assign(".SealedClasses", c(get(".SealedClasses", where), "SClassExtension"), where);
}

.simpleExtCoerce <- function(from, strict = TRUE)from
.simpleIsCoerce <- function(from)from
.simpleExtTest <- function(object)TRUE
## TO DO:  the simple replace below only handles the case of classes with slots.
## There are some other simple relations (e.g., with virtual classes).  Replacing in
## these cases is less likely but needs to be tested (below) and a suitable
## replace function inserted.
.simpleExtReplace <- function(from, to, value){
    for(what in .InhSlotNames(to))
        slot(from, what) <- slot(value, what)
    from
}
## slot names for inheritance (to be used in replace methods).  Extends slots to implicit
## .Data for basic classes.
.InhSlotNames <- function(Class) {
   ClassDef <- getClass(Class)
    value <- names(ClassDef@slots)
    if(length(value)==0 && (Class %in% .BasicClasses || extends(ClassDef, "vector")))
        ## No slots, but extends "vector" => usually a basic class; treat as data part
        value <- ".Data"
   value
}
.dataPartReplace <- function(from, to, value){
    from@.Data <- value
    from
}

.dataPartReplace2 <- function(from, to, value){
    from@.Data <- as(value, THISCLASS, strict = FALSE)
    from
}

## and a version of dataPartReplace w/o the unused `to' argument
.dataPartReplace2args <- function(from, value) {
    from@.Data <- value
    from
}
    
.ErrorReplace <- function(from, to, value)
    stop(paste("No replace method was defined for as(x, \"", to,
               "\") <- value for class \"", class(from), "\"", sep=""))

.objectSlotNames <- function(object) {
    ## a quick version that makes no attempt to check the class definition
    value <- names(attributes(object))
    if(is.null(value)) ## not possible with methods package?
        character()
    else
        value[-match("class", value, 0)]
}

makeExtends <- function(Class, to,
                        coerce = NULL, test = NULL, replace = NULL,
                        by = character(), package,
                        slots = names(getSlots(classDef1)),
                        classDef1 = getClass(Class), classDef2) {
    ## test for datapart class:  must be the data part class, except
    ## that extensions within the basic classes are allowed (numeric, integer)
    dataEquiv <- function(cl1, cl2) {
        .identC(cl1, cl2) ||
          (extends(cl1, cl2) && !any(is.na(match(c(cl1, cl2), .BasicClasses))))
    }
    class1Defined <- missing(slots) # only at this time can we construct methods
    simple <- is.null(coerce) && is.null(test) && is.null(replace) && (length(by)==0)
    dataPartClass <- elNamed(slots, ".Data")
    dataPart <- FALSE
    if(simple && !is.null(dataPartClass)) {
        if(isClass(dataPartClass) && isClass(to)) {
            ## note that dataPart, to are looked up in the methods package & parents:
            ## Assertion is that only these classes are allowed as data slots
            dataPart <- dataEquiv(dataPartClass, to)
        }
    }
    if(is.null(coerce)) {
        coerce <- .simpleExtCoerce
        if(!isVirtualClass(classDef2))
            body(coerce, envir = environment(coerce)) <-
                 .simpleCoerceExpr(Class, to, slots, classDef2)
    }
    else if(is(coerce, "function")) {
        ## we allow definitions with and without the `strict' argument
        ## but create a  function that can be called with the argument
        if(length(formals(coerce)) == 1) {
            coerce <- .ChangeFormals(coerce, .simpleIsCoerce, "`coerce' argument to setIs ")
            tmp <- .simpleExtCoerce
            body(tmp, envir = environment(coerce)) <- body(coerce)
            coerce <- tmp
        }
        else
            coerce <- .ChangeFormals(coerce, .simpleExtCoerce, "`coerce' argument to setIs ")
        
    }
    else stop("The `coerce' argument to setIs should be a function of one argument, got an object of class \"",
              class(coerce), "\"")
    if(is.null(test))
        test <- .simpleExtTest
    else
        test <- .ChangeFormals(test, .simpleExtTest, "`test' argument to setIs ")
    if(is.null(replace)) {
        if(dataPart) {
            extn <- elNamed(classDef2@contains, dataPartClass)
            if(is(extn, "SClassExtension"))
                easy <- extn@simple
            else
                easy <- FALSE
            if(easy)
                replace <- .dataPartReplace
            else {
                replace <- .dataPartReplace2
                bdy <- body(replace)
                body(replace, envir = environment(replace)) <-
                    substituteDirect(bdy, list(THISCLASS = dataPartClass))
            }
        }
        else if(simple) {
            replace <- .simpleExtReplace
            if(isVirtualClass(classDef2)) {  # a simple is to a virtual class => a union
                body(replace, envir = environment(replace)) <-
                    substitute({
                        if(!is(value, TO))
                            stop("The computation: as(object,\"", TO,
                                 "\") <- value is valid when object has class",
                                 FROM, "\" only if is(value, \"",TO,"\") is TRUE ( class(value) was \"",
                                 class(value), "\")")
                        value
                    }, list(FROM = Class, TO = to))
            }
            else if(class1Defined && length(slots) == 0) {
                ## check for Class, to having the same representation
                ## (including the case of no slots)
                ext <- getAllSuperClasses(classDef1)
                toSlots <- classDef2@slots
                sameSlots <- TRUE
                for(eclass in ext)
                    if(!.identC(eclass, to) && isClass(eclass) &&
                       length(getClassDef(eclass)@slots) > 0) {
                        sameSlots <- FALSE
                        break
                    }
                if(sameSlots)
                    body(replace, envir = environment(replace)) <-
                        substitute({class(value) <- FROM; value}, list(FROM = Class))
                else if(length(toSlots) == 0) # seems replacement not defined in this case?
                    replace <- .ErrorReplace
            }
        }
        else
            replace <- .ErrorReplace
        if(identical(replace, .ErrorReplace))
            warning("There is no automatic definition for as(object, \"", to,
                    "\") <- value when object has class \"", Class,
                    "\" and no replace= argument was supplied; replacement will be an error")
    }
    else if(is(replace, "function")) {
        ## turn function of two or three arguments into correct 3-arg form
        if(length(formals(replace)) == 2) {
            replace <- .ChangeFormals(replace, .dataPartReplace2args, "`replace' argument to setIs ")
            tmp  <- .ErrorReplace
            body(tmp, envir = environment(replace)) <- body(replace)
            replace <- tmp
        }
        else
            replace <- .ChangeFormals(replace, .ErrorReplace, "`replace' argument to setIs ")
    }
    else
        stop("the replace= argument to setIs() should be a function of 2 or 3 arguments, got an object of class \"",
             class(replace), "\"")
    new("SClassExtension", subClass = Class, superClass = to, package = package, coerce = coerce,
               test = test, replace = replace, simple = simple, by = by, dataPart = dataPart)
    
    
}

.findAll <- function(what, where = topenv(parent.frame())) {
    ## search in envir. & parents thereof
    ## must avoid R's find() function because it uses
    ## regular expressions
    value <- list()
    if(is.environment(where))
        repeat {
            if(exists(what, where, inherits = FALSE))
                value <- c(value, list(where))
            ## two forms of test for the end of the parent env. chain
            if(isBaseNamespace(where) || is.null(where))
                break
            where <- parent.env(where)
        }
    else
        for(i in where) {
            if(exists(what, i, inherits = FALSE))
                value <- c(value, list(i))
        }
    value
}
    
