/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/tools/repairer/GarbageCheck.java,v 1.2 2004/12/15 10:38:27 pnever Exp $
 * $Revision: 1.2 $
 * $Date: 2004/12/15 10:38:27 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed 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.slide.store.tamino.tools.repairer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import org.apache.slide.store.tamino.datastore.XPathFactory;
import org.apache.slide.store.tamino.jdomobjects.XDescriptors;
import org.apache.slide.store.tamino.jdomobjects.XUuri;
import org.apache.slide.store.tamino.tools.stores.XStore;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.util.XException;
import org.apache.slide.util.XUri;


public class GarbageCheck extends AbstractCheck implements RepairConstants {
    private final String rootUuri;
    private final String lostAndFoundUuri;
    
    protected GarbageCheck(XStore main, XTaminoClient taminoClient) throws XException {
        super(taminoClient, MSG_START_GARBAGE_CHECK, MSG_DESCR_GARBAGE_CHECK);

        // TODO: doesn't work for special stores
        this.rootUuri = XUuri.getStoreUuri(main.useBinding(), new XUri(main.getName()));
        this.lostAndFoundUuri = rootUuri; // TODO
    }
    
    public void check() throws XException {
        Map allUuris;
        Collection uuris;
        String uuri;
        
        allUuris = taminoClient.getDescriptorsAccessor().getUurisMap(XPathFactory.uuris( taminoCollection )); // inoId -> uuri
        uuris = new ArrayList(allUuris.values());
        // TODO: remove all stores in this group
        removeReachable(rootUuri, uuris);
        removeStoreUuris(uuris);
        while (!uuris.isEmpty()) {
            uuri = getTop(uuris);
            removeReachable(uuri, uuris);
            revitalize(taminoClient.getDescriptorsAccessor(), lostAndFoundUuri, uuri);
        }
    }

    private void removeStoreUuris(Collection uuris) {
        Iterator iter;
        String uuri;
        
        iter = uuris.iterator();
        while (iter.hasNext()) {
            uuri = (String) iter.next();
            if (XUuri.isStoreUuri(uuri)) {
                iter.remove();
            }
        }
    }
    
    private String getTop(Collection uuris) throws XException {
        String uuri;
        String next;
        
        for (uuri = (String) uuris.iterator().next(); true; uuri = next) {
            next = getNextTop(uuri, uuris);
            if (next == null) {
                return uuri;
            }
            uuri = next;
        }
    }
    
    private String getNextTop(String uuri, Collection uuris) throws XException {
        XDescriptors desc;
        Enumeration parents;
        ObjectNode.ParentBinding b;
        
        desc = taminoClient.getDescriptorsAccessor().readDescriptorsByUuri(uuri);
        parents = desc.getUuriObjectNode().enumerateParentBindings();
        while (parents.hasMoreElements()) {
            b = (ObjectNode.ParentBinding) parents.nextElement();
            if (uuris.contains(b.getUuri())) {
                return b.getUuri();
            }
        }
        return null;
    }
    
    private void removeReachable(String uuri, Collection unreached) throws XException {
        XDescriptors desc;
        Enumeration en;
        
        if (unreached.remove(uuri)) {
            desc = taminoClient.getDescriptorsAccessor().readOneRwDescriptorsByUuri(uuri);
            en = desc.getUuriObjectNode().enumerateBindings();
            while (en.hasMoreElements()) {
                removeReachable(((ObjectNode.Binding) en.nextElement()).getUuri(), unreached);
            }
        } else {
            // to nothing, already visited
        }
    }
    
}

