package net.bblfish.triples.test;

import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;

import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;


/**
 * Date: May 6, 2004
 * Time: 10:33:01 PM
 * author: hjs
 */
public class Blog3Example {
    Model worldModel = ModelFactory.createDefaultModel();
    static SimpleDateFormat df, tagf, filef;
    Model entryDB = ModelFactory.createDefaultModel();
    ArrayList entries = new ArrayList();
    String base = "http://bblfish.net/work/atom-owl/2004-08-12/";

    static {
        df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); //ISO 8601 format
        df.getTimeZone().setID("+00:00");
        tagf = new SimpleDateFormat("yyyyMMdd/HHmm");
        filef = new SimpleDateFormat("yyyy-MM-dd-HHmm");

    }


    void publish() {
        File name = new File("AllInOneDatabase.n3");
        entryDB.setNsPrefix("", Atom.NS);
        entryDB.setNsPrefix("xsd", XSDDatatype.XSD + "#");
        entryDB.setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
        try {
            entryDB.write(new FileOutputStream(name), "N3-PP", name.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    class Feed {
        File dir;
        String fileprefix;
        int numEntries;

        Resource id;
        private String lang;

        /**
         * A feed will contain a certain number of entries.
         *
         * @param fileprefix the file prefix, which will be followed by .n3 for the changing part of the feed and
         *                   a time stamp for the archived version
         * @param numEntries the number of entries in each feed file
         */
        public Feed(String fileprefix, int numEntries) {
            this.fileprefix = fileprefix;
            this.numEntries = numEntries;
        }

        void init() {

        }

        Resource about;
        void setAbout(Resource about) {
            this.about = about;
        }

        void setLanguage(String lang) {
            this.lang = lang;
        }


        /*
        void addFeedEntry(Entry entry) {
            entries.add(entry);
            feedRes.addProperty(Atom.feedEntry, entry.entryRes);
        }
          */

        /*
        void addNextLink(Entry e) {
        } */

        void writeAsHtml() {
            try {
                Writer html = new FileWriter(new File("blogexample.html"));
                html.write("<html>\n" +
                        "<head>\n" +
                        "</head>\n" +
                        "<body>");
                html.write("<table border='1'>");
                header.writeEntryAsHtml(html);
                html.write("</table>");
                List topentries = new ArrayList(getTopLevelEntries());
                topentries.remove(header);
                Collections.sort(topentries);
                Collections.reverse(topentries);
                for (Iterator i = topentries.iterator(); i.hasNext();){
                    Entry e = (Entry)i.next();
                    e.writeAsHtml(html);
                }
                html.write("</body></html>");
                html.flush();
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }

        }

        /**
         *
         * @return all entries that are not in reply to something else
         */
        private Set getTopLevelEntries() {
            Set result = new HashSet();
            for (Iterator i = entries.iterator(); i.hasNext();) {
                Entry e = (Entry)i.next();
                if (!e.model.listSubjectsWithProperty(Atom.in_reply_to).hasNext())
                    result.add(e);
            }
            return result;
        }


        void publish(Resource dynamicRes, File file, List entries, File next) throws FileNotFoundException {
            Model model = ModelFactory.createDefaultModel();
            Resource feedRes = model.createResource(base+file.toString(), Atom.Feed);
            feedRes.addProperty(Atom.header,header.entryRes);
            feedRes.addProperty(Atom.about,about);
            feedRes.addProperty(Atom.dynamic,dynamicRes);

            Statement stmt;
            for (Iterator it = entries.iterator(); it.hasNext();) {
                Entry e = (Entry) it.next();
                feedRes.addProperty(Atom.entry, e.entryRes);
                stmt = model.createStatement(e.entryRes,Atom.id,e.id);
                model.add(stmt);
                stmt = model.createStatement(e.entryRes,Atom.entry_version,e.entryVersion);
                model.add(stmt);
            }

            if (next != null) {
                Resource linkRes = model.createResource(Atom.Link);
                linkRes.addProperty(Atom.mime_type, model.createTypedLiteral("application/rdf+n3"));
                linkRes.addProperty(Atom.text, model.createTypedLiteral("previous " + numEntries + " entries"));
                Resource lnk = model.createResource(base+next.toString());
                linkRes.addProperty(Atom.href, lnk);

                feedRes.addProperty(Atom.previous, linkRes);
            }

            model.setNsPrefix("", Atom.NS);
            model.setNsPrefix("xsd", XSDDatatype.XSD + "#");
            model.setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
            model.write(new FileOutputStream(file), "N3-PP", file.toString());
        }

        void publish() throws FileNotFoundException {
            Resource feed = entryDB.createResource(base+fileprefix + ".n3");
            feed.addProperty(RDF.type, Atom.Feed);

            System.out.println("num entries:" + entries.size());
            for (int i = 0; i < entries.size(); i++) {
                Entry e = (Entry) entries.get(i);
                if (e == null)
                    System.out.println(i + "=null");
                else
                    System.out.println(e.nameN3);
            }
            Collections.sort(entries);
            Collections.reverse(entries);
            File oldfile = null;
            for (int i = 0; i+numEntries < entries.size(); i += numEntries) {
                List todo = entries.subList(i, i+numEntries);
                File file = new File(fileprefix + "-entries_" + i +"_to_"+ (i+numEntries-1) + ".n3");
                publish(feed, file, todo, oldfile);
                oldfile = file;
            }

            List todo = entries.subList(Math.max(0, entries.size() - numEntries), entries.size());
            publish(feed, new File(fileprefix + ".n3"), todo, oldfile);
        }


        Entry header;
        public void setHeaderEntry(Entry entry) {
            this.header = entry;
        }


        class Link {
            Resource linkRes;

            Link(String rel, String mime, String href) {
            }

            Resource getResource() {
                return linkRes;
            }
        }


    }

    class Blog {
        Model model = ModelFactory.createDefaultModel();
        Resource blogRes;
        File file = new File("blog.n3");

        Blog() {
            blogRes = model.createResource(base+file.toString());
            blogRes.addProperty(RDF.type,Atom.Blog);
            blogRes.addProperty(Atom.post_service,model.createResource(base+"Blog3Example.java"));
            blogRes.addProperty(Atom.version, "Atom 0.6");//does this make sense to have a version at this level? Why is that not at the top level of the xml?
            blogRes.addProperty(Atom.generator, "TripledBlog version 0.6");
            blogRes.addProperty(Atom.lang, "en"); //would it be possible to add xml:lang here (instead of Atom.lang)?
            blogRes.addProperty(Atom.info, "This blog is an example blog to test out how one could create a blogging " +
                    "standard using the very powerful Semantic Web tools. Note that the post-service for this blog is" +
                    " currently the java file that generated all these files. This is a joke of course. In an easy to use" +
                    " blogging tool, one would not have to edit a java file, compile it, then run it in order to add a new entry.");
        }

        void publish() throws FileNotFoundException {
             model.setNsPrefix("", Atom.NS);
             model.setNsPrefix("xsd", XSDDatatype.XSD + "#");
             model.setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
             model.write(new FileOutputStream(file), "N3-PP", file.toString());
         }

    }

    class Entry implements Comparable {
        File nameN3;
        File nameRDF;
        File simpleRDF;
        Model model = ModelFactory.createDefaultModel();
        Resource entryRes;
        Resource id;
        Resource entryVersion;
        Set responses = new HashSet();

/*        String rules = "[r1: (?e "+Atom.id + " ?id) -> (?id "+ RDF.type + " " + Atom.EntryID + ")] "+
                "[r2: (?e "+ Atom.author +" ?author), (?e "+Atom.id + " ?id) -> (?id "+ Atom.author +" ?author)]" +
                "[r2: (?e "+ Atom. +" ?author), (?e "+Atom.id + " ?id) -> (?id "+ Atom.author +" ?author)]" +
*/
        

        Entry(Date created) {
            this.nameN3 = new File("entry." + filef.format(created) + ".n3");
            nameRDF = new File("entry." + filef.format(created) + ".rdf");
            simpleRDF = new File("atom." + filef.format(created) + ".rdf");
            entryRes = model.createResource(base+nameN3.toString());
            id = model.createResource("tag:bblfish.net/" + tagf.format(created) + "/blog1");
            entryVersion = model.createResource(id + "#version1");


            entryRes.addProperty(RDF.type, Atom.Entry);
            entryRes.addProperty(Atom.id, id);
            entryRes.addProperty(Atom.entry_version, entryVersion);

            Resource linkRes = model.createResource(Atom.Link);
              linkRes.addProperty(Atom.mime_type, model.createTypedLiteral("text/html"));
              linkRes.addProperty(Atom.text, model.createTypedLiteral("html blog entry"));
              Resource lnk = model.createResource(base+"blogexample.html#"+nameN3.toString());
             linkRes.addProperty(Atom.href, lnk);


            entryRes.addProperty(Atom.alternate,linkRes);

            Statement stmt = entryDB.createStatement(id, RDF.type, Atom.EntryID);
            entryDB.add(stmt);

            stmt = entryDB.createStatement(entryVersion, RDF.type, Atom.EntryVersion);
            entryDB.add(stmt);

            stmt = entryDB.createStatement(id, Atom.state, entryVersion);
            entryDB.add(stmt);

            stmt = entryDB.createStatement(entryVersion, Atom.entry_location, entryRes);
            entryDB.add(stmt);

            StmtIterator i = linkRes.listProperties();
            entryDB.add(i);
            stmt = entryDB.createStatement(entryVersion, Atom.alternate, linkRes);
            entryDB.add(stmt);

            entries.add(this);

            setCreated(created);
        }

        void addResponse(Entry other) {
            Statement stmt = entryDB.createStatement(other.id, Atom.in_reply_to, entryVersion);
            entryDB.add(stmt);

            stmt = other.model.createStatement(other.entryRes, Atom.in_reply_to, entryVersion);
            other.model.add(stmt);

            // we need to state where the id can be found to which this is a response
            stmt = other.model.createStatement(entryVersion, Atom.entry_location, entryRes);
            other.model.add(stmt);

            responses.add(other);
        }


        Person author;

        void setAuthor(Person author) {
            this.author = author;
            model.add(author.statements());
            entryRes.addProperty(Atom.author, author.getResource());


            entryDB.add(author.statements());
            Statement stmt = entryDB.createStatement(id, Atom.author, author.getResource());
            entryDB.add(stmt);
        }

        void addContributor(Person contr) {
            model.add(contr.statements());
            entryRes.addProperty(Atom.contributor, contr.getResource());

            entryDB.add(contr.statements());
            Statement stmt = entryDB.createStatement(entryRes, Atom.contributor, contr.getResource());
            entryDB.add(stmt);
        }

        void addCopyright() {
            entryRes.addProperty(Atom.copyright, entryDB.createResource("http://creativecommons.org/licenses/by-sa/2.0/"));
        }


        Resource getResource() {
            return entryRes;
        }

        public int compareTo(Object o) {
            Entry e = (Entry) o;
            return e.creationDate.compareTo(creationDate);
        }

        String title;

        void setTitle(String title) {
            this.title = title;
            Content titleCnt = new Content(title, "text/simple");
            entryRes.addProperty(Atom.title, titleCnt.getResource());

            Statement stmt = entryDB.createStatement(entryVersion, Atom.title, titleCnt.getResource());
            entryDB.add(stmt);

        }

        Date creationDate;

        private void setCreated(Date date) {
            this.creationDate = date;
            entryRes.addProperty(Atom.created, getDateLiteral(date));

            Statement stmt = entryDB.createStatement(id, Atom.created, getDateLiteral(date));
            entryDB.add(stmt);
        }

        Literal getDateLiteral(Date date) {
            String formattedDate = df.format(date);
            Literal d = model.createTypedLiteral(formattedDate, XSDDatatype.XSDdateTime);
            return d;
        }

        String body;

        void setBody(String body) {
            this.body = body;
            Content bodyCnt = new Content(body, "text/html");
            entryRes.addProperty(Atom.content, bodyCnt.getResource());

            Statement stmt = entryDB.createStatement(entryVersion, Atom.content, bodyCnt.getResource());
            entryDB.add(stmt);
        }

        void writeAsHtml(Writer out) throws IOException {
            System.out.println("Number of responses for " + entryRes + ": " + responses.size());
            out.write("<table border='1'>");
            writeEntryAsHtml(out);
            if (responses.size() > 0) {
                List resLst = new ArrayList(responses);
                out.write("<tr><td bgcolor='FFFCC'><font>responses</font></td><td colspan='15'><table border='1'>");
                Collections.sort(resLst);
                if (inverse) Collections.reverse(resLst);
                for (Iterator i = resLst.iterator(); i.hasNext();) {
                    Entry e = (Entry) i.next();
                    e.writeAsHtml(out);
                }
            }
            out.write("</table>");
        }


        boolean inverse = true;

        void invert() {
            inverse = !inverse;
        }


        void writeEntryAsHtml(Writer out) throws IOException {
            out.write("<tr id="+nameN3.toString()+"><td bgcolor='teal'><font color='white'>title</font></td><td bgcolor='silver' colspan='15'>" + title + "</td>");
            out.write("<tr><td bgcolor='teal'><font color='white'>author</font></td><td bgcolor='silver'>" + author.name + "</td>");
            out.write("<td bgcolor='gray'>created</td><td bgcolor='silver'>" + creationDate.toGMTString() + "</td>");
            out.write("<td bgcolor='gray'>N3 file</td><td bgcolor='silver'><a href='" + nameN3 + "'>"+nameN3+"</a></td>");
            out.write("<td bgcolor='gray'>RDF file</td><td bgcolor='silver'><a href='" + nameRDF + "'>"+nameRDF+"</a></td>");
            out.write("<td bgcolor='gray'>Atom-like RDF file</td><td bgcolor='silver'><a href='" + simpleRDF + "'>"+simpleRDF+"</a></td>");
            out.write("<tr><td></td><td colspan='15'>" + body + "</td>");
            out.write("<tr bgcolor='black'><td></td><td colspan='15'></td>");
        }


        class Content {
            Resource content;
            String text;

            Content(String text, String mime) {
                this.text = text;
                content = model.createResource(Atom.Content);
                Literal val = model.createTypedLiteral(text);

                Statement stmt = entryDB.createStatement(content, Atom.mime_type, model.createTypedLiteral(mime));
                entryDB.add(stmt);
                model.add(stmt);
                stmt = entryDB.createStatement(content, Atom.data, val);
                entryDB.add(stmt);
                model.add(stmt);
            }

            Resource getResource() {
                return content;
            }

        }


        void publish() throws FileNotFoundException {
            model.setNsPrefix("", Atom.NS);
            model.setNsPrefix("xsd", XSDDatatype.XSD + "#");
            model.setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
            model.setNsPrefix("foaf","http://xmlns.com/foaf/0.1/");

            model.write(new FileOutputStream(nameN3), "N3-PP", base);
            model.write(new FileOutputStream(nameRDF), "RDF/XML-ABBREV", base);

            Model simple = ModelFactory.createDefaultModel();
            simple.setNsPrefix("", Atom.NS);
            simple.setNsPrefix("xsd", XSDDatatype.XSD + "#");
            simple.setNsPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
            simple.setNsPrefix("foaf","http://xmlns.com/foaf/0.1/");

            simple.add(model);
            StmtIterator it = simple.listStatements(new SimpleSelector() {
                public boolean selects(Statement statement) {
                    try {
                    statement.getLiteral();
                        return true;
                    } catch (Exception e) {
                        return false; //pretty ugly way of coding
                    }
                }
            });
            ArrayList todelete = new ArrayList();
            ArrayList toAdd = new ArrayList();
            while (it.hasNext()) {
                Statement st = it.nextStatement();
                Literal l = st.getLiteral();
                if (l.getDatatype() != null) {
                    Literal nl = simple.createLiteral(l.getString());
                    Statement result = model.createStatement( st.getSubject(),st.getPredicate(),(RDFNode)nl);
                    todelete.add(st);
                    toAdd.add(result);
                }
            }
            simple.remove(todelete);
            simple.add(toAdd);
           // NodeIt it = model.listObjectsOfProperty();
            simple.write(new FileOutputStream(simpleRDF),"RDF/XML-ABBREV", base);
        }

    }

    class Person {
        Statement[] statements = new Statement[4];
        Resource personRes;

        String name;

        Person(String name, String email, String url) {
            this.name = name;
            personRes = worldModel.createResource(FOAF.Agent);
            Resource webPage = worldModel.createResource(url);
            statements[3] = worldModel.createStatement(personRes, RDF.type, FOAF.Person);
            Literal nameLit = worldModel.createTypedLiteral(name);
            statements[0] = worldModel.createStatement(personRes, FOAF.name, nameLit);
            Resource emailRes = worldModel.createResource("mailto:" + email);
            statements[1] = worldModel.createStatement(personRes, FOAF.mbox, emailRes);
            statements[2] = worldModel.createStatement(personRes, FOAF.homepage, webPage);
        }

        Resource getResource() {
            return personRes;
        }

        public Statement[] statements() {
            return statements;
        }
    }


    public static void main(String[] args) throws FileNotFoundException {
        Blog3Example b2 = new Blog3Example();

        Person henry = b2.new Person("Henry Story", "henry.story@bblfish.net", "http://bblfish.net/");
        Person hjs = b2.new Person("H. Story", "hjs@bblfish.net", "http://bblfish.net/");
        Person danny = b2.new Person("Danny Ayers", "danny666@virgilio.it", "http://dannyayers.com/");
        Person asbjorn = b2.new Person("Asbjorn Ulsberg", "asbjorn@tigerstaden.no", "http://asbjorn.no/");
        Person bob = b2.new Person("bob wyman", "bob@wyman.us", "http://wyman.us");
        Person ken = b2.new Person("Ken McLeod", "ken@bitsko.slc.ut.us", "http://bitsko.slc.ut.us/blog");

        Blog blog = b2.new Blog();
        blog.publish();

        Entry headEntry = b2.new Entry(new Date(104, 5, 29, 10, 10, 0));
        headEntry.addCopyright();
        headEntry.setAuthor(henry);
        headEntry.setTitle("A Blog on combining Atom and FOAF");
        headEntry.setBody(" This is an example blog to illustrate what a fully semantic weblog could look like. Instead of using RSS" +
                " or Atom content for the feed, I show here how one can create a very powerful, flexible and easy to understand system" +
                " based on Semantic Web Triples, presented for clarity in <a href='http://infomesh.net/2002/notation3/'>N3 format</a>" +
                " and backed up by an <a href='http://www.w3.org/TR/owl-ref/'>OWL ontology</a>.<p>" +
                " This project is a continuation of the work by Danny Ayers on " +
                " <a href='http://semtext.org/atom/atom-semweb.htm'>Atom+OWL</a>, but it does not feel the need to stay so close to the Atom " +
                " specification, and is more interested in using all the tools available to the Semantic Web developer to show how much" +
                " further one can go in this direction, than it is in convincing people in the Atom community that there is a simple mapping " +
                " from their work to this one. By integrating with the rest of the Semantic Web community one can also more clearly" +
                " describe the true contribution of Atom: by refactoring Danny's simple mapping, and extracting elements that are" +
                " better addressed by other OWL libraries (such as <a href='http://xmlns.com/foaf/0.1/'>FOAF</a>), we can locate the" +
                " core of Atom.<p> Another difference concerns the role of standards. Whereas Atom which is aiming to create a standard " +
                " format for blogging, this method is following in the spirit of the FOAF group, " +
                " an attempt to create something like a software library, " +
                " in the spirit of an Open Source project." );

        Entry entry0_1 = b2.new Entry(new Date(104, 6, 12, 19, 35, 0));
              entry0_1.addCopyright();
              entry0_1.setAuthor(henry);
              entry0_1.setTitle("Copyrights");
              entry0_1.setBody("All of the content here" +
                " is freely licenced under the gpl for the code, and the <a href='http://creativecommons.org/licenses/by-sa/2.0/'>" +
                      "Attribution-ShareAlike 2.0</a> Creative Commons license, for the text. ");


        Entry entry0_2 = b2.new Entry(new Date(104, 6, 12, 19, 45, 0));
        entry0_2.addCopyright();
        entry0_2.setAuthor(henry);
        entry0_2.setTitle("A Note on Format");
        entry0_2.setBody("This research is presented in blog format, so that it can itself be a test case for the" +
                " format it is advocating. The <a href='blogexample.html'>html presentation of this blog</a> does not" +
                " follow the usual blogging tradition of presenting the main entries in inverse chronological order, as " +
                " this would make following the flow of ideas presented here a little awkward. " +
                "  <p>Blog entries are written by Henry Story, as well as the replies which were added to illustrate" +
                 " threading. All of html and N3 files contained in <a href='.'>this directory</a> " +
                 " were generated by a <a href='Blog3Example.java'>little java program</a> available in the same directory. " +
                 " Some of the noteworthy files are: <ul>" +
                 " <li> <a href='Atom.owl'>Atom.owl</a> and <a href='Atom.n3'>Atom.n3</a> the formal OWL spec which backs this" +
                 "   all up." +
                 " <li> <a href='AllInOneDatabase.n3'>AllInOneDatabase.n3</a> a file that contains all the entries. More on this below." +
                 " <li> <a href='feed.n3'>feed.n3</a> which is the dynamic entry point to the feed for this blog. The other 'feedxxx.n3'" +
                 " files are feed archives." +
                 " <li> Each of the entry.xxx.n3 files that describe each of the entries of this blog." +
                 " </ul> " +
                " <p>This model is the second attempt and tries to incorporate all the lessons learned from the" +
                " <a href='http://bblfish.net/work/atom-owl/2004-06-22/blogexample.html'>first one</a>");


        Entry entry1 = b2.new Entry(new Date(104, 7, 12, 20, 35, 0));
        entry1.addCopyright();
        entry1.setAuthor(henry);
        entry1.setTitle("An overview UML diagram");
        entry1.setBody("Here is a partially simplified UML diagram of Atom-FOAF. <p>" +
                "<img src='Atom-FOAF-overview.jpg'><p> The reality is a little" +
                " more complicated because there are in fact two ways to represent an Entry:" +
                "<ul>" +
                "  <li> the simple default one shown here" +
                "  <li> another way that takes into account the possible states an Entry can have over time." +
                "</ul>" +
                " There is a simple logical relation between the two views, which I will get into in a later blog" +
                " entry.<p>" +
                " Two important things to notice here are the yellow and green background zones. <br>" +
                " The classes on the green background come from the <a href='http://xmlns.com/foaf/0.1/'>FOAF</a> " +
                " namespace. Those on the yellow background have until recently been thought to belong to the Atom " +
                " namespace. It is my contention here (arrived at after a long conversation with Ken McLeod) that these Feed" +
                " classes are in fact much more general, and don't in any particular way belong to Atom. We can find " +
                " similar structures in many places we look on the web - pretty much anywhere we need to " +
                " chunk a potentially large list of results into smaller sections - such as for example" +
                " search engine results, WebDav search results(?)... So this is a first attempt at " +
                " simplification. By pushing out everything Atom related into the Blog class located on the white background" +
                " reserved for Atom concepts, we end up with a little 'Feed'" +
                " structure that could be nicely useful elsewhere (after due renaming perhaps) and with a Blog class " +
                " where we can place a lot of the 'introspection' information. <p>" +
                " The UML diagram is of course backed up by the formally specified <a href='Atom.owl'>Atom OWL spec</a>" +
                " that ships with this release.");

        Entry entry1_0 = b2.new Entry(new Date(104, 7, 13, 5, 30, 0));
        entry1_0.addCopyright();
        entry1_0.setAuthor(bob);
        entry1_0.setTitle("It's all about the Entries, stupid!");
        entry1_0.setBody("This also very nicely illustrates what I was trying to get at with my " +
                "<a href='http://www.imc.org/atom-syntax/mail-archive/msg04596.html'>It's about the Entries, Stupid!</a>" +
                " post I sent a few months back. By simplifying the model down to the core it becomes apparent that" +
                " it is indeed the Entry that is at the core of Atom.  The person and the Feed concepts are not" +
                " central to Atom. They are generic concepts that can be found and used elsewhere.");
        entry1.addResponse(entry1_0);


        Entry entry1_1 = b2.new Entry(new Date(104, 7, 13, 10, 47, 0));
        entry1_1.addCopyright();
        entry1_1.setAuthor(hjs);
        entry1_1.setTitle("N3 illustration - The Feed");
        entry1_1.setBody("To start off let us look at the feed files. There are two sets of these files:" +
                "<ul>" +
                "<li><code><a href='feed.n3'>feed.n3</a></code>, which is the head of the feed, the dynamic file that changes" +
                " whenever a new entry is added to the blog. This is the file that blog readers will be polling every" +
                " so often." +
                "<li><code><a href='feed-entries_0_to_3.n3'>feed-entries_0_to_3.n3</a></code>, <code>feed-entries_x_to_y.n3</code>,... " +
                " each of which is an archive of older" +
                " feed entries. These files <b>SHOULD NOT</b> change, making them prime candidates for cacheing." +
                "</ul>" +
                " Each of these files is a part of the whole result. I don't yet have a concept yet the union of all the " +
                " content in these files. This may be something that needs adding. Each file points to the previous " +
                " results with code such as  <br><code><pre>  " +
                "  &lt;&gt;   :previous\n" +
                "              [ a       :Link ;\n" +
                "                :href   &lt;feed-entries_0_to_3.n3&gt; ;\n" +
                "                :mime-type \"application/rdf+n3\"^^xsd:string ;\n" +
                "                :text   \"previous 4 entries\"^^xsd:string \n" +
                "              ] .\n" +
                " </pre></code><br> " +
                " which says that the previous entries can be found at the resource <code>&lt;feed-entries_0_to_3.n3&gt;</code>." +
                " <code>&lt;feed-entries_0_to_3.n3&gt;</code> itself points to the dynamic element of the feed thus <br><code><pre>" +
                "  &lt;&gt;   a       :Feed ;\n" +
                "      :about  &lt;blog.n3&gt; ;\n" +
                "      :dynamic &lt;feed.n3&gt; ;\n" +
                "</pre></code><br>" +
                " which points to the dynamic part of the feed. It also points to the blog file that contains" +
                " the so called 'introspection' information about the blog: namely where the url for adding new entries" +
                " is located, and other things which I know are not yet fully thought through.<p>" +
                " <b>Notice</b>: The current feeds contain <b>very little</b> information. They  point" +
                " to the entries themselves. <code>feed.n3</code> for example points to four (only four for illustrative" +
                " purposes) entries as shown here:" +
                "  <br><code><pre>" +
                "&lt;&gt;    a       :Feed ;\n" +
                "      :dynamic &lt;&gt; ;\n" +
                "      :entry  &lt;entry.2004-08-13-1047.n3&gt; , &lt;entry.2004-08-13-1445.n3&gt; ,\n " +
                "              &lt;entry.2004-08-13-1752.n3&gt; , &lt;entry.2004-08-13-1632.n3&gt; ;\n" +
                "</pre></code><br>" +
                " To help clients tell which entries they have or have not downloaded we can add further information" +
                " such as the EntryID and the EntryVersion of each of these entries. That is done further down in the" +
                " <code>feed.n3</code> file:" +
                "  <br><code><pre>" +
                 "&lt;entry.2004-08-13-1047.n3&gt;\n" +
                "      :entry-version &lt;tag:bblfish.net/20040813/1047/blog1#version1&gt; ;\n" +
                "      :id     &lt;tag:bblfish.net/20040813/1047/blog1&gt; .\n" +
                "\n" +
                "&lt;entry.2004-08-13-1445.n3&gt;\n" +
                "      :entry-version &lt;tag:bblfish.net/20040813/1445/blog1#version1&gt; ;\n" +
                "      :id     &lt;tag:bblfish.net/20040813/1445/blog1&gt; ." +
                "</pre></code><br>" +
                " Clearly a lot more could be added. One could add the title (an obvious addition), perhaps the publication date, " +
                " the last changed" +
                " date... One could of course add everything, as with the <a href='AllInOneDatabase.n3'>AllInOneDatabase.n3</a>," +
                " but that would be extreemely wasteful in bandwidth and very un-" +
                "<a href='http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm'>REST</a>ful. What to add and not to add" +
                " is really an empirical research topic. Having very little information is not really a problem. As long as the" +
                " client can  determine where the entries are and which entries it allready has fetched (hence the entry-version field) it will only" +
                " need to fetch the content once. With " +
                " HTTP 1.1 Persistent Connections, having to make multiple requests is not at all a problem. "
                 );
        entry1.addResponse(entry1_1);

        Entry entry2 = b2.new Entry(new Date(104, 7, 13, 14, 45, 0));
        entry2.addCopyright();
        entry2.setAuthor(henry);
        entry2.setTitle("Two perspectives on a blog entry");
        entry2.setBody("The current model proposes two view on an entry: <ul>" +
                "<li>the simple Entry, that can be found at a certain retrievable location, and shows only its current state." +
                "<li>the Entry as a historical thing, that encompasses all the changes that occurred to it in the actual" +
                "world (we don't deal with <a href='http://en.wikipedia.org/wiki/David_Lewis_%28philosopher%29'>counterfactual" +
                "</a> entries). This is the EntryID and its associated EntryVersion-s." +
                "</ul>" +
                "This is illustrated by the following diagram:<p>" +
                "<img src='Atom-FOAF-twoEntries.jpg'>" +
                "<p>" +
                "Again I have tried to highlight the two areas by placing their classes on differently colored backgrounds." +
                " On the yellow background is the main class for the temporal Entry representation, and on the green background, we" +
                " have the atemporal Entry Representation. Given any one of these one can deduce the other. Ie, they are " +
                " logical consequences of one another.<p>" +
                " Some of the main points distinguishing them are: <ul>" +
                " <li> An entry has a URL resource, that allows one to fetch the information (for example a " +
                " relative uri such as <a href='entry.2004-06-29-1010.n3'>entry.2004-06-29-1010.n3</a>), " +
                " whereas EntryID and EntryVersions are URNs such as <u>tag:bblfish.net/20040629/1010/blog1#version1</u>" +
                " which will indeed uniquely identify an Entry, but will not allow one to retrieve them without a search" +
                " engine. This difference creates a fundamental difference in use between these two ways of looking at the" +
                " entry. An Entry is what people should be editing and fetching in a RESTful manner using GET, POST, and PUT." +
                " An EntryID is how a client would identify the Entry-s it downloaded to keep track of the changes to them," +
                " and that to which they were responding, so it could follow how the entry " +
                " propagated around the web, etc. The EntryID and EntryState classes are key elements in databases such as" +
                " <a href='AllInOneDatabase.n3'>AllInOneDatabase.n3</a>, which contains all the information about all the " +
                " entries in this directory. " +
                " <li> An entry must have an id and of course an entry-version. The unchanging parts of the Entry, its " +
                " essential properties, go into the EntryID structure. The contingent properties of an Entry go into the" +
                " EntryVersion. An EntryID may on the other hand have a number of EntryVersion-s. Each of these EntryVersions" +
                " represents the state of the Entry over a particular span of time. From an Entry one can easily deduce the EntryVersion" +
                " and EntryID fields. To go in the opposite direction one first needs to select the latest EntryVersion of an EntryID." +
                " <li>An Entry can be a reply to another EntryVersion. It is important to keep track of which version of an" +
                " entry one is replying to, as this can significantly change the meaning of a response. For clients this could" +
                " help clients flag responses that might need to be updated or even deleted, or it could help readers beware that" +
                " a response may no longer be relevant to the entry it is relating to."+
                " </ul>" +
                "");

        Entry entry2_0 = b2.new Entry(new Date(104, 7, 13, 16, 32, 0));
        entry2_0.addCopyright();
        entry2_0.setAuthor(hjs);
        entry2_0.setTitle("Graphical illustration of the two pespectives");
        entry2_0.setBody("Let me illustrate two views on an Entry graphically, so as not to have to take any sides among" +
                " the many possible serialisations of semantic web triples: N3, N-Triples, RDF, ... Each of these serialisation formats can" +
                " be mapped onto a graph of triples, as explained in the w3c's <a href='http://www.w3.org/TR/rdf-mt/'>RDF Semantics</a>" +
                " paper. I here represent resources in rounded rectangles, blank nodes by circles, Literals by rectangles, and of course" +
                " predicates by named arrows.<p>" +
                " Let us start off with a simple graphical representation of an Entry written in a file " +
                " <code>entry1.n3</code>, written by Karl Dubost, where he asserts the" +
                " cryptic '2b v not2b'. <br><img src='Atom-FOAF-ExampleEntry-1.jpg'><br>" +
                " The <code>id</code> of the entry is <code>tag:e1</code>, and it is the first version as hinted at by the " +
                " <code>entry-version</code> which is <code>tag:e1#v1</code>. The entry was created on 11 Jun 2002 at 5pm, and" +
                " was published (<code>issued</code>) shortly thereafter, at 10 minutes past 5. (Note that since we know that the entry is written" +
                " by Karl Dubost, we may be able to find who is friends are if we have access to some FOAF files that mention him.)<p>" +
                " Perhaps shortly later Karl finds that he wants to make a change to his entry. He prefers titles to start with" +
                " capitals, and changes his statement to a question. He is still thinking about this change, so this" +
                " change does not yet have a publication date. (how we got this file is of course a problem for my story now)." +
                " As a result the graph we have is as follows:<br>" +
                "<img src='Atom-FOAF-ExampleEntry-2.jpg'><br>" +
                " Here I have highlighted in green the changes to the graph. Gone is the issued field, a modified date has" +
                " appeared, and the data fields of the title and entry fields have slightly changed. Of course we have a new" +
                " version id.<p>" +
                " Any person who fetches " +
                " <code>entry1.n3</code> after the change (and after he issues it) will not be able to retrieve the original version, " +
                " as it will have been" +
                " completely replaced by the new one. They will know when the file was last modified though. But if someone were to keep track" +
                " of all these changes - either the editor that Karl is using in order to allow him to backtrack to previous versions" +
                " were he to think he had made a mistake, or some agregator that wanted to keep a fuller view of the changes made to the" +
                " posts on Karl's web site (perhaps in order to notify the aggregator's owner that a reply he wrote to Ken's post had changed) -" +
                " then he would presumably want to keep the changes stored in its local database by organising the entries by EntryID, in " +
                " a database similar to our <a href='AllInOneDatabase.n3'>AllInOneDatabase.n3</a>. The graph for this entry would then" +
                " look like this:<br>" +
                "<img src='Atom-FOAF-ExampleEntry-3.jpg'><br>" +
                 " Here the root of the tree is the <code>EntryID</code>, which points to the two <code>EntryVersion</code>s." +
                " Notice that in this case the <code>EntryVersion</code>s have an <code>entry-location</code>, to help" +
                " find the original entry file. The location is" +
                " not attached to the <code>EntryID</code> as the location of an Entry could change over time. In this case " +
                " the entry has remained in the same position.<p>" +
                " It should be very easy to specify a logical relation allowing one to deduce one of the views from the other. " +
                " Since we are speaking in ontology, there is not concptual priority of one of these views over the other. They" +
                " both exist simultaneously.");
        entry2.addResponse(entry2_0);



        Entry entry2_1 = b2.new Entry(new Date(104, 7, 13, 17, 52, 0));
        entry2_1.addCopyright();
        entry2_1.setAuthor(hjs);
        entry2_1.setTitle("N3 illustration on the two pespectives");
        entry2_1.setBody("The entry file using the Entry class is pretty easy to understand. As an example let us take the " +
                "file describing this entry, namely <a href='entry.2004-08-13-1752.n3'>entry.2004-08-13-1752.n3</a>." +
                "<br><code><pre>  " +
                "&lt;&gt;    a       :Entry ;\n" +
                "      :author [ a       &lt;http://xmlns.com/foaf/0.1/Person&gt; ;\n" +
                "                &lt;http://xmlns.com/foaf/0.1/homepage&gt;\n" +
                "                        &lt;http://bblfish.net/&gt; ;\n" +
                "                &lt;http://xmlns.com/foaf/0.1/mbox&gt;\n" +
                "                        &lt;mailto:hjs@bblfish.net&gt; ;\n" +
                "                &lt;http://xmlns.com/foaf/0.1/name&gt;\n" +
                "                        \"H. Story\"^^xsd:string\n" +
                "              ] ;" +
                "</pre></code><br>" +
                " The first line just specifies that this file ('&lt;&gt;' in N3) is an Entry. It then continues" +
                " by specifying the author of the Entry using the FOAF classes. Everything else in the file is" +
                " pretty self evident. Perhaps the following requires a little closer look at" +
                "<br><code><pre>" +
                "      :id     &lt;tag:bblfish.net/20040813/1752/blog1&gt; ;\n" +
                "      :entry-version &lt;tag:bblfish.net/20040813/1752/blog1#version1&gt; ;\n" +
                "      :in-reply-to &lt;tag:bblfish.net/20040813/1445/blog1#version1&gt; ;\n" +
                "      :title  [ a       :Content ;\n" +
                "                :data   \"N3 illustration on the two pespectives\"^^rdf:string ;\n" +
                "                :mime-type \"text/simple\"^^xsd:string\n" +
                "              ] .\n" +
                "</pre></code><br>" +
                " Here we specify the id and entry-version tags. Notice that with a well designed URI structure one" +
                " should be able to guess the id tag from the version tag. Here the version tag just consists of the" +
                " entry id with '#version1' appended.<p>" +
                " Notice the <code>in-reply-to</code> property. It relates the current Entry not to another Entry (with" +
                " a URL) but to antother EntryVersion. How do we retrieve the location of the EntryVersion to which this" +
                " Entry is a reply? Well further down in the file we have the following statement: " +
                "<br><code><pre>  " +
                "&lt;tag:bblfish.net/20040813/1445/blog1#version1&gt;\n" +
                "      :entry-location &lt;entry.2004-08-13-1445.n3&gt; ." +
                "</pre></code><br>" +
                " which associate that entry version with a Entry URL namely the above <a href='entry.2004-08-13-1445.n3'>" +
                "entry.2004-08-13-1445.n3</a>.<p>" +
                " How does this Entry appear in the <a href='AllInOneDatabase.n3'>AllInOneDatabase.n3</a>? We just need to" +
                " search that file for the EntryID <code>tag:bblfish.net/20040813/1752/blog1</code>" +
                "<br><code><pre>" +
                "&lt;tag:bblfish.net/20040813/1752/blog1&gt;\n" +
                "      a       :EntryID ;\n" +
                "      :author _:b2 ;\n" +
                "      :created \"2004-08-13T17:52:00+0200\"^^xsd:dateTime ;\n" +
                "      :in-reply-to &lt;tag:bblfish.net/20040813/1445/blog1#version1&gt; ;\n" +
                "      :state  &lt;tag:bblfish.net/20040813/1752/blog1#version1&gt; ."+
                "</pre></code><br>" +
                " This just gives us the author <code>_:b2</code> wich is an empty node that is specified" +
                " in more detail elsewhere in the file, the creation time, what this EntryId was in reply to," +
                " and the EntryState tag. The values for that tag are also to be found in the file, and its content should" +
                " correspond to the text you are now reading." +
                " ");
        entry2.addResponse(entry2_1);


        entry1.publish();
        headEntry.publish();
        entry0_1.publish();
        entry0_2.publish();
        entry1_0.publish();
        entry1_1.publish();
        entry2.publish();
        entry2_0.publish();
         entry2_1.publish();

        Feed feed = b2.new Feed("feed", 4);
        feed.setLanguage("en");
        feed.setHeaderEntry(headEntry);
        feed.setAbout(blog.blogRes);
        feed.publish();
        feed.writeAsHtml();

        b2.publish();

    }
}
