/*
* Copyright 2015 Shashank Tulsyan <shashaank at neembuu.com>.
*
* 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 spyfs;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.atomic.AtomicBoolean;
import jpfm.AccessLevel;
import jpfm.DirectoryStream;
import jpfm.FileDescriptor;
import jpfm.FileFlags;
import jpfm.FileId;
import jpfm.FileType;
import jpfm.fs.ReadOnlyRawFileData;
import jpfm.operations.readwrite.ReadRequest;
import jpfm.operations.readwrite.SimpleReadRequest;
import jpfm.volume.RealFile;
import jpfm.volume.RealFileProvider;
import jpfm.volume.vector.VectorNode;
import neembuu.rangearray.RangeArray;
import neembuu.rangearray.RangeArrayFactory;
import neembuu.rangearray.RangeArrayParams;
import neembuu.rangearray.RangeUtils;
/**
*
* @author Shashank
*/
public class SpiedFile implements RealFile {
private final RealFile rf;
private final Path dest;
private final RangeArray ra;
private volatile boolean opened = false;
public SpiedFile(Path p,VectorNode parent,Path destBase) throws IOException{
rf = RealFileProvider.getNonBlockingRealFile(p.toAbsolutePath().toString(),parent);
this.dest = destBase;
ra = RangeArrayFactory.newDefaultRangeArray(new RangeArrayParams.Builder<>().build());
}
@Override
public String getSourceFile() {
return rf.getSourceFile();
}
@Override
public void close() {
try{
if(fc!=null)fc.close();
fc = null;
}catch(Exception a){
a.printStackTrace();
}
rf.close();
}
@Override
public boolean isOpenByCascading() {
return rf.isOpenByCascading();
}
@Override
public void open() {
opened = true;
rf.open();
}
FileChannel fc = null;
public Path getDest() {
return dest;
}
public boolean opened(){
return opened;
}
public String p(){
Object[]pz=px();
String ret = (String)pz[1];
double ps = (Double)pz[0];
return ps+"\t"+ret;
}
private Object[] px(){
double sz = 0d;
String ret = "";
ret+="{";
for (int i = 0; i < ra.size(); i++) {
sz+=RangeUtils.getSize(ra.get(i));
ret+=","+ra.get(i);
}ret+="}";
return new Object[]{(sz/(getFileSize()*1d)),ret};
}
@Override public void read(ReadRequest read) throws Exception {
if(!Files.exists(dest.getParent())){
Files.createDirectories(dest.getParent());
}if(fc==null){
fc = FileChannel.open(dest, StandardOpenOption.CREATE,StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING);
}
rf.read(read);
//write(read);
ra.addElement(read.getFileOffset(), read.getFileOffset()+read.getByteBuffer().capacity() -1,this);
}
private void write(ReadRequest read)throws Exception{
try{
ByteBuffer bb = ByteBuffer.allocate(read.getByteBuffer().capacity());
SimpleReadRequest srr = new SimpleReadRequest(bb, read.getFileOffset());
rf.read(srr);
while(!srr.isCompleted()){Thread.sleep(10);}
bb.limit(bb.capacity());bb.rewind();
while(fc.position()!=read.getFileOffset()){
fc.position(read.getFileOffset());
}
fc.write(bb);
fc.force(true);
}catch(Exception a){
a.printStackTrace();
}
}
public void export()throws IOException{
double ps = (Double)px()[0];
if(ps>0){
if(!Files.exists(dest.getParent())){
Files.createDirectories(dest.getParent());
}
Files.copy(Paths.get(rf.getSourceFile()), dest,StandardCopyOption.REPLACE_EXISTING);
}else if(opened){// the file was just opened, but not read
if(!Files.exists(dest)){
if(!Files.exists(dest.getParent())){
Files.createDirectories(dest.getParent());
}
Files.createFile(dest);
}
}
}
@Override
public void setCannotClose(boolean cannotClose) {
rf.setCannotClose(cannotClose);
}
@Override
public DirectoryStream getParent() {
return rf.getParent();
}
@Override
public FileType getFileType() {
return rf.getFileType();
}
@Override
public FileDescriptor getFileDescriptor() {
return rf.getFileDescriptor();
}
@Override
public long getFileSize() {
return rf.getFileSize();
}
@Override
public long getCreateTime() {
return rf.getCreateTime();
}
@Override
public long getAccessTime() {
return rf.getAccessTime();
}
@Override
public long getWriteTime() {
return rf.getWriteTime();
}
@Override
public long getChangeTime() {
return rf.getChangeTime();
}
@Override
public String getName() {
return rf.getName();
}
@Override
public FileDescriptor getParentFileDescriptor() {
return rf.getParentFileDescriptor();
}
@Override
public FileFlags getFileFlags() {
return rf.getFileFlags();
}
@Override
public ReadOnlyRawFileData getReference(FileId fileId, AccessLevel level) {
return rf.getReference(fileId, level);
}
}