/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.riot.process.normalize;

import java.util.HashMap ;
import java.util.Map ;
import java.util.function.Function;

import org.apache.jena.datatypes.RDFDatatype ;
import org.apache.jena.datatypes.xsd.XSDDatatype ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.NodeFactory ;
import org.apache.jena.riot.web.LangTag ;
import org.apache.jena.sparql.util.NodeUtils ;
import org.apache.jena.vocabulary.RDF ;

public class CanonicalizeLiteral implements Function<Node, Node>    
{
    private static final CanonicalizeLiteral singleton = new CanonicalizeLiteral(); 

    public static CanonicalizeLiteral get() { return singleton ; }

    private CanonicalizeLiteral() {}
    
    @Override
    public Node apply(Node node) {
        if ( ! node.isLiteral() )
            return node ;
            
        RDFDatatype dt = node.getLiteralDatatype() ;
        Node n2 ;
        if ( NodeUtils.isLangString(node) ) {
            // RDF 1.0, no datatype ; RDF 1.1 : datatype is rdf:langString 
            if ( node.getLiteralLanguage().equals("") )
                //n2 = NormalizeValue.dtSimpleLiteral.handle(node, node.getLiteralLexicalForm(), null) ;
                return node ;
            else
                n2 = canonicalLangtag(node.getLiteralLexicalForm(), node.getLiteralLanguage()) ; 
        } else if ( dt == null ) {
            // RDF 1.0 / no lang.
            n2 = NormalizeValue.dtSimpleLiteral.handle(node, node.getLiteralLexicalForm(), null) ;
        } else {
            // Dataype, not rdf:langString (RDF 1.1). 
            DatatypeHandler handler = dispatch.get(dt) ;
            if ( handler == null )
                return node ;
            n2 = handler.handle(node, node.getLiteralLexicalForm(), dt) ;
        }
        
        if ( n2 == null )
            return node ;
        return n2 ;
    }
    
    private static Node canonicalLangtag(String lexicalForm, String langTag)
    {
        String langTag2 = LangTag.canonical(langTag) ;
        if ( langTag2.equals(langTag) )
            return null ;
        return NodeFactory.createLiteral(lexicalForm, langTag2) ;
    }
    
    private static final RDFDatatype dtPlainLiteral = NodeFactory.getType(RDF.getURI()+"PlainLiteral") ;
    
    private final static Map<RDFDatatype, DatatypeHandler> dispatch = new HashMap<>() ;

    // MUST be after the handler definitions as these assign to statics, so it's code lexcial order.
    // or use static class to force touching that, initializing and then getting the values. 
    static {
        dispatch.put(XSDDatatype.XSDinteger,                NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDdecimal,                NormalizeValue.dtDecimal) ;

        // Subtypes. Changes the datatype.
        dispatch.put(XSDDatatype.XSDint,                    NormalizeValue.dtInteger) ;        
        dispatch.put(XSDDatatype.XSDlong,                   NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDshort,                  NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDbyte,                   NormalizeValue.dtInteger) ;

        dispatch.put(XSDDatatype.XSDunsignedInt,            NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDunsignedLong,           NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDunsignedShort,          NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDunsignedByte,           NormalizeValue.dtInteger) ;

        dispatch.put(XSDDatatype.XSDnonPositiveInteger,     NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDnonNegativeInteger,     NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDpositiveInteger,        NormalizeValue.dtInteger) ;
        dispatch.put(XSDDatatype.XSDnegativeInteger,        NormalizeValue.dtInteger) ;

        dispatch.put(XSDDatatype.XSDfloat,      NormalizeValue.dtFloat ) ;
        dispatch.put(XSDDatatype.XSDdouble,     NormalizeValue.dtDouble ) ;

        // Only fractional seconds part can vary for the same value. 
        dispatch.put(XSDDatatype.XSDdateTime,   NormalizeValue.dtDateTime) ;
        
        // These are fixed format 
//        dispatch.put(XSDDatatype.XSDdate,       null) ;
//        dispatch.put(XSDDatatype.XSDtime,       null) ;
//        dispatch.put(XSDDatatype.XSDgYear,      null) ;
//        dispatch.put(XSDDatatype.XSDgYearMonth, null) ;
//        dispatch.put(XSDDatatype.XSDgMonth,     null) ;
//        dispatch.put(XSDDatatype.XSDgMonthDay,  null) ;
//        dispatch.put(XSDDatatype.XSDgDay,       null) ;

        dispatch.put(XSDDatatype.XSDduration,   null) ;
        dispatch.put(XSDDatatype.XSDboolean,    NormalizeValue.dtBoolean) ;
        
        dispatch.put(XSDDatatype.XSDstring,     NormalizeValue.dtXSDString) ;

        
        dispatch.put(dtPlainLiteral,            NormalizeValue.dtPlainLiteral) ;
        
    }
}

@@ -2745,20 +2745,16 @@
 langTag)
-%0A   
  %7B%0A     
@@ -2800,17 +2800,16 @@
 langTag)
- 
 ;%0A      
@@ -2865,17 +2865,16 @@
 urn null
- 
 ;%0A      
@@ -2930,25 +2930,24 @@
 angTag2)
- 
 ;%0A    %7D%0A
     %0A   
@@ -2930,36 +2930,32 @@
 angTag2);%0A    %7D%0A
-    
 %0A    private sta
@@ -5516,32 +5516,92 @@
 ean) ;%0A        %0A
+        // Convert to RDF 1.1 form - no explicit datatype. %0A
         dispatch
@@ -5662,25 +5662,82 @@
 ring) ;%0A
-%0A
+ 
        
- 
+// Convert (illegal) rdf:PlainLiteral to a legal RDF term.
 %0A       
@@ -5806,29 +5806,20 @@
 nLiteral) ;%0A
-        %0A
     %7D%0A%7D%0A

Add comments + reformat.